cejs
Version:
A JavaScript module framework that is simple to use.
1,770 lines (1,634 loc) • 267 kB
JavaScript
/**
* @name CeL function for astronomical calculations.
* @fileoverview 本檔案包含了天文演算用的日期轉換功能。
*
* @since 2015/3/20 23:5:43
*
* TODO:
*
* 1. 座標全改 radians
*
* 2. 黃→視黃→赤→(視)赤→地平座標
*
* http://eclipse.gsfc.nasa.gov/JSEX/JSEX-index.html
* https://web.archive.org/web/http://www.chris.obyrne.com/Eclipses/calculator.html
* https://en.wikipedia.org/wiki/Astronomical_symbols
*
* calculate Halley's Comet 哈雷彗星
*
* Software & coded<br />
* http://www.kentauren.info/menu/index1.htm?page=/cgi-bin/planeph_VSOP87d.pl
* https://pypi.python.org/pypi/astronomia
* https://github.com/Hedwig1958/libastro/blob/master/astro.c
* https://github.com/soniakeys/meeus/blob/master/solar/solar.go
* https://github.com/hkuno9000/sunmoon/blob/master/acoord.cpp
* http://www.timeanddate.com/calendar/moonphases.html
* http://eco.mtk.nao.ac.jp/koyomi/
*
* 大地測量:給定地球表面兩個點的經緯度,計算兩點間之距離<br />
* 天球上天體/星體距離<br />
* http://geographiclib.sourceforge.net/scripts/geod-calc.html
* http://wywu.pixnet.net/blog/post/27459116
* http://iotresearch.wikispaces.com/GPS<br />
* Andoyer 方法最大的誤差約為50公尺,Lambert 方法最大的誤差約30m。
* http://usenrong.iteye.com/blog/2147341
* http://en.wikipedia.org/wiki/Haversine_formula
* http://en.wikipedia.org/wiki/Spherical_law_of_cosines
* http://en.wikipedia.org/wiki/Vincenty's_formulae
*
* LUNAR SOLUTION ELP version ELP/MPP02
*
* 未來發展:<br />
*
* @see <a href="http://www.nongli.com/item2/index.html" accessdate="2013/5/2
* 20:23">农历知识:传统节日,24节气,农历历法,三九,三伏,天文历法,天干地支阴阳五行</a>
* @see <a href="http://www.chinesefortunecalendar.com/CLC/clcBig5.htm"
* accessdate="2013/5/2 20:23">如何轉換陰陽曆</a>
*
* 簡易朔望/天象計算功能/千年 節氣 計算。<br />
* http://bieyu.com/<br />
* http://www.fjptsz.com/xxjs/xjw/rj/117/index.htm
*
* 通用万年历 寿星万年历 择吉老黄历 http://www.todayonhistory.com/wnl/lhl.htm
*
*/
'use strict';
// 'use asm';
// More examples: see /_test suite/test.js
// ------------------------------------------------------------------------------------------------------------------//
// 不採用 if 陳述式,可以避免 Eclipse JSDoc 與 format 多縮排一層。
typeof CeL === 'function' && CeL.run({
// module name
name : 'application.astronomy',
require : 'data.code.compatibility.'
// data.math.find_root()
// data.date.Date_to_JD()
+ '|data.math.polynomial_value|data.date.',
// 為了方便格式化程式碼,因此將 module 函式主體另外抽出。
code : module_code
});
function module_code(library_namespace) {
// requiring
var polynomial_value = this.r('polynomial_value');
/**
* full module name.
*
* @type {String}
*/
var module_name = this.id;
/**
* null module constructor
*
* @class astronomical calculations 的 functions
*/
var _// JSDT:_module_
= function() {
// null module constructor
};
/**
* for JSDT: 有 prototype 才會將之當作 Class
*/
_// JSDT:_module_
.prototype = {};
// ------------------------------------------------------------------------------------------------------//
// basic constants. 定義基本常數。
var
/** {Number}未發現之index。 const: 基本上與程式碼設計合一,僅表示名義,不可更改。(=== -1) */
NOT_FOUND = ''.indexOf('_'),
/**
* 周角 = 360°, 1 turn, 1 revolution, 1 perigon, full circle, complete
* rotation, a full rotation in degrees.
*
* @type {Number}
*/
TURN_TO_DEGREES = 360 | 0,
/**
* 周角.
*
* TURN_TO_RADIANS = 2πr/r = 2π =
* 6.283185307179586476925286766559005768394338798750211641949889...
*
* @type {Number}
*
* @see https://en.wikipedia.org/wiki/Radian
*/
TURN_TO_RADIANS = 2 * Math.PI,
/**
* degrees * DEGREES_TO_RADIANS = radians.
*
* DEGREES_TO_RADIANS = 2π/360 =
* 0.017453292519943295769236907684886127134428718885417254560971... ≈
* 1.745329251994329576923691e-2
*
* @type {Number}
*/
DEGREES_TO_RADIANS = TURN_TO_RADIANS / TURN_TO_DEGREES,
/**
* degrees * DEGREES_TO_ARCSECONDS = arcseconds.
*
* DEGREES_TO_ARCSECONDS = 3600
*
* @type {Number}
*/
DEGREES_TO_ARCSECONDS = 60 * 60 | 0,
/**
* Arcseconds in a full circle. 角秒
*
* TURN_TO_ARCSECONDS = 1296000
*
* @type {Number}
*/
TURN_TO_ARCSECONDS = TURN_TO_DEGREES * DEGREES_TO_ARCSECONDS,
/**
* arcseconds * ARCSECONDS_TO_RADIANS = radians.
*
* ARCSECONDS_TO_RADIANS = 2π/360/3600 =
* 0.0000048481368110953599358991410235794797595635330237270151558... ≈
* 4.848136811095359935899141e-6
*
* @type {Number}
*/
ARCSECONDS_TO_RADIANS = DEGREES_TO_RADIANS / DEGREES_TO_ARCSECONDS,
/**
* 24: 24 hours @ 1 day
*/
ONE_DAY_HOURS = 24,
/**
* Seconds per day. 每一天 86400 秒鐘。
*
* @type {Number}
*/
ONE_DAY_SECONDS = ONE_DAY_HOURS * 60 * 60 | 0;
// ---------------------------------------------------------------------//
// 天文相關定常數。
var
/**
* 每年 2 分點 + 2 至點。
*
* EQUINOX_SOLSTICE_COUNT = 4
*
* @type {Number}
*/
EQUINOX_SOLSTICE_COUNT = 2 + 2,
/**
* 每分至點 90°。
*
* EQUINOX_SOLSTICE_DEGREES = 90
*
* @type {Number}
*/
EQUINOX_SOLSTICE_DEGREES
//
= TURN_TO_DEGREES / EQUINOX_SOLSTICE_COUNT,
/** {Array}二十四節氣名。每月有一個節氣,一個中氣,分別發生在每月的7日和22日前後。 */
SOLAR_TERMS_NAME =
// Chinese name: 中氣,節氣,中氣,節氣,...
'春分,清明,穀雨,立夏,小滿,芒種,夏至,小暑,大暑,立秋,處暑,白露,秋分,寒露,霜降,立冬,小雪,大雪,冬至,小寒,大寒,立春,雨水,驚蟄'
.split(','),
/**
* 每年 24節氣。
*
* SOLAR_TERMS_COUNT = 24
*
* @type {Number}
*/
SOLAR_TERMS_COUNT = SOLAR_TERMS_NAME.length,
/**
* 每節氣 15°。
*
* DEGREES_BETWEEN_SOLAR_TERMS = 15
*
* @type {Number}
*/
DEGREES_BETWEEN_SOLAR_TERMS = TURN_TO_DEGREES / SOLAR_TERMS_COUNT,
// 🌑NEW MOON SYMBOL
// 🌒WAXING CRESCENT MOON SYMBOL
// ☽FIRST QUARTER MOON
// 🌓FIRST QUARTER MOON SYMBOL
// 🌔WAXING GIBBOUS MOON SYMBOL
// 🌕FULL MOON SYMBOL
// 🌖WANING GIBBOUS MOON SYMBOL
// 🌙CRESCENT MOON
// ☾LAST QUARTER MOON
// 🌗LAST QUARTER MOON SYMBOL
// 🌘WANING CRESCENT MOON SYMBOL
// 🌚NEW MOON WITH FACE
/**
* 各種月相: 新月、上弦月、滿月、下弦月。
*/
LUNAR_PHASE_NAME = [
// gettext_config:{"id":"new-moon"}
"朔",
// gettext_config:{"id":"first-quarter"}
"上弦",
// gettext_config:{"id":"full-moon"}
"望",
// gettext_config:{"id":"last-quarter"}
"下弦" ],
/**
* 本地之 time zone / time offset (UTC offset by minutes)。<br />
* e.g., UTC+8: 8 * 60 = +480<br />
* e.g., UTC-5: -5 * 60
*
* @type {Number}
*/
default_offset = library_namespace.String_to_Date
//
&& library_namespace.String_to_Date.default_offset
|| -(new Date).getTimezoneOffset() || 0;
_.SOLAR_TERMS = SOLAR_TERMS_NAME;
// ---------------------------------------------------------------------//
// Astronomical constant 天文常數。
// @see https://en.wikipedia.org/wiki/Astronomical_constant
// @see https://github.com/kanasimi/IAU-SOFA/blob/master/src/sofam.h
// @see
// http://asa.usno.navy.mil/static/files/2015/Astronomical_Constants_2015.txt
var
/**
* Reference epoch (J2000.0), Julian Date. J2000.0 曆元。
*
* DAYS_OF_JULIAN_CENTURY = (365 + 1/4) * 100
*
* @type {Number}
*
* @see https://en.wikipedia.org/wiki/Epoch_%28astronomy%29#Julian_years_and_J2000
*/
J2000_epoch = 2451545.0,
/**
* Days per Julian century. 儒略世紀.
*
* DAYS_OF_JULIAN_CENTURY = (365 + 1/4) * 100
*
* @type {Number}
*/
DAYS_OF_JULIAN_CENTURY = 36525,
/**
* speed of light in vacuum (m/s), c 光速.
*
* @type {Number}
*/
CELERITAS = 299792458,
/**
* Astronomical unit (meters).<br />
* 1 astronomical unit = 149597870700 meters (exactly)
*
* Astronomical Almanac 2011:<br />
* au = A = 149597870700 ± 3 m
*
* @type {Number}
*/
AU_TO_METERS = 149597870700,
/**
* Light-time for unit (AU) distance (in days).<br />
* AU_LIGHT_TIME = 149597870700/299792458/86400 ≈ 0.005775518331436995
*
* @type {Number}
*/
AU_LIGHT_TIME = AU_TO_METERS / CELERITAS / ONE_DAY_SECONDS,
/**
* Earth mean radius (meter). 地球平均半徑(公尺)。地球半徑6,357km到6,378km。
*
* @type {Number}
*
* @see https://en.wikipedia.org/wiki/Earth_radius#Mean_radius
*/
TERRA_RADIUS_M = 6371009,
/**
* Equatorial radius of Earth (meter). 地球赤道半徑(公尺)。
*
* IERS (2003),<br />
* Astronomical Almanac 2011:<br />
* a_E = a_e = 6378136.6 ± 0.10 m
*
* @type {Number}
*
* @see https://en.wikipedia.org/wiki/Earth_ellipsoid#Historical_Earth_ellipsoids
*/
TERRA_EQUATORIAL_RADIUS_M = 6378136.6,
/**
* Polar radius of Earth (meter). 地球極半徑(公尺)。
*
* IERS (2003):<br />
*
* @type {Number}
*
* @see https://en.wikipedia.org/wiki/Earth_ellipsoid#Historical_Earth_ellipsoids
*/
TERRA_POLAR_RADIUS_M = 6356751.9,
/**
* Earth's flattening = 1 / (Reciprocal of flattening).<br />
* 地球偏率 = 1 - 極半徑/赤道半徑
*
* IERS (2003): 1 / 298.25642
*
* @type {Number}
*
* @see https://en.wikipedia.org/wiki/Earth_ellipsoid#Historical_Earth_ellipsoids
*/
TERRA_FLATTENING = 1 / 298.25642,
/**
* 月球平均半徑 in meter (公尺)。
*
* @type {Number}
*
* @see http://en.wikipedia.org/wiki/Moon
*/
LUNAR_RADIUS_M = 1737100,
/**
* 地月平均距離 in meter (公尺)。
*
* 平均距離 mean distance: 384400 km (公里)<br />
* 半長軸 Semi-major axis: 384748 km (公里)<br />
*
* @type {Number}
*
* @see https://en.wikipedia.org/wiki/Lunar_distance_%28astronomy%29
* @see http://en.wikipedia.org/wiki/Orbit_of_the_Moon
* @see http://solarsystem.nasa.gov/planets/profile.cfm?Display=Facts&Object=Moon
*/
LUNAR_DISTANCE_M = 384400000,
/**
* Geocentric semi-diameter of the Sun (in radians) 日面的平均地心視半徑。
* 960″.12±0″.09 (696, 342±65km).
*
* old: 959.63 arcseconds.<br />
* 0°16′ should be added for the semidiameter.<br />
* average apparent radius of the Sun (16 arcminutes)
*
* @type {Number}
*
* @see http://arxiv.org/pdf/1203.4898v1.pdf
* @see http://arxiv.org/pdf/1106.2537.pdf
* @see http://aa.usno.navy.mil/faq/docs/RST_defs.php
* @see https://en.wikipedia.org/wiki/Solar_radius
*/
SOLAR_RADIUS_ARCSECONDS = 960.12,
//
SOLAR_RADIUS_RADIANS = SOLAR_RADIUS_ARCSECONDS * ARCSECONDS_TO_RADIANS,
/**
* Geocentric semi-diameter of the Sun (in m) 日面的平均地心視半徑。
*
* Math.atan(696342000 / 149597870700) / (2 * Math.PI) * 360 * 60 ≈ 16′
*
* @type {Number}
*/
SOLAR_RADIUS_M = 696342000,
/**
* Constant of aberration (arcseconds). κ 光行差常數
*
* 天文學中定義周年光行差常數(簡稱光行差常數)為κ=v/c,其中c是光速,v是地球繞太陽公轉的平均速度
*
* Astronomical Almanac 2011:<br />
* Constant of aberration at epoch J2000.0:<br />
* kappa = 20.49551″
*
* @type {Number}
*
* @see https://zh.wikipedia.org/wiki/%E5%85%89%E8%A1%8C%E5%B7%AE
*/
ABERRATION_κ = 20.49551;
// ---------------------------------------------------------------------//
// 初始調整並規範基本常數。
// ---------------------------------------------------------------------//
// private tool functions. 工具函數
/**
* 經緯度 pattern [ , °, ′, ″, ″., NEWS ]
*
* @type {RegExp}
*/
var LATITUDE_PATTERN, LONGITUDE_PATTERN;
(function() {
/**
* 經緯度 pattern [ , °, ′, ″, ″., NEWS ]
* <q>/([+\-]?\d+(?:\.\d+)?)°\s*(?:(\d+)[′']\s*(?:(\d+(?:\.\d+)?)(?:″|"|'')(\.\d+)?\s*)?)?([NEWS])/i</q>
*/
var d = /([+\-]?\d+(?:\.\d+)?)°\s*/, ms =
//
/(?:(\d+)[′']\s*(?:(\d+(?:\.\d+)?)(?:″|"|'')(\.\d+)?\s*)?)?/;
LATITUDE_PATTERN = new RegExp(d.source + ms.source + '([NS])', 'i');
LONGITUDE_PATTERN = new RegExp(d.source + ms.source + '([EW])', 'i');
})();
// 經緯度
// [ {Number}latitude 緯度, {Number}longitude 經度 ]
function parse_coordinates(coordinates) {
var latitude, longitude,
// e.g., '25.032969, 121.565418'
matched = coordinates.match(
//
/([+\-]?\d+(?:\.\d+)?)(?:\s+|\s*,\s*)([+\-]?\d+(?:\.\d+)?)/);
if (matched)
return [ +matched[1], +matched[2] ];
// e.g., 25° 1′ 58.6884″ N 121° 33′ 55.5048″ E
// e.g., 25° 1' 58.6884'' N 121° 33' 55.5048'' E
matched = coordinates.match(LATITUDE_PATTERN);
if (matched) {
latitude = +matched[1] + (matched[2] ? matched[2] / 60 : 0)
+ (matched[3] ? matched[3] / 60 / 60 : 0)
+ (matched[4] ? matched[4] / 60 / 60 : 0);
if (matched[5].toUpperCase() === 'S')
latitude = -latitude;
}
matched = coordinates.match(LONGITUDE_PATTERN);
if (matched) {
longitude = +matched[1] + (matched[2] ? matched[2] / 60 : 0)
+ (matched[3] ? matched[3] / 60 / 60 : 0)
+ (matched[4] ? matched[4] / 60 / 60 : 0);
if (matched[5].toUpperCase() === 'W')
longitude = -longitude;
}
if (latitude || longitude)
return [ latitude, longitude ];
}
_.parse_coordinates = parse_coordinates;
/**
* get Julian centuries since J2000.0.<br />
* J2000.0 起算的儒略世紀數.<br />
* Interval between fundamental date J2000.0 and given date.
*
* @param {Number}TT_JD
* Julian date (JD of 天文計算用時間 TT)
*
* @returns {Number} Julian centuries of JD from J2000.0
*/
function Julian_century(TT_JD) {
return (TT_JD - J2000_epoch) / DAYS_OF_JULIAN_CENTURY;
}
_.Julian_century = Julian_century;
// normalize degrees
// to proper degrees 0–less than 360
// near_0: −180–less than 180
function normalize_degrees(degrees, near_0) {
if (!degrees)
return degrees;
if ((degrees %= TURN_TO_DEGREES) < 0)
degrees += TURN_TO_DEGREES;
if (near_0 && degrees >= TURN_TO_DEGREES / 2)
degrees -= TURN_TO_DEGREES;
return degrees;
}
_.normalize_degrees = normalize_degrees;
function normalize_radians(radians, near_0) {
if (!radians)
return radians;
radians = radians.mod(TURN_TO_RADIANS);
if (near_0 && radians >= TURN_TO_RADIANS / 2)
radians -= TURN_TO_RADIANS;
return radians;
}
_.normalize_radians = normalize_radians;
/**
* 將時分秒轉成 radians。
*
* @param {Number}hours
* @param {Number}minutes
* @param {Number}seconds
* @param {Boolean}to_days
* 轉成 days (turns)。
* @param {Boolean}is_degrees
* 輸入的是 degrees
*
* @returns {Number}radians
*/
function time_to_radians(hours, minutes, seconds, to_days, is_degrees) {
if (seconds)
minutes = (minutes || 0) + seconds / 60;
hours = ((hours || 0) + (minutes ? minutes / 60 : 0))
// to days
/ (is_degrees ? TURN_TO_DEGREES : ONE_DAY_HOURS);
if (!to_days)
hours *= TURN_TO_RADIANS;
return hours;
}
_.time_to_radians = time_to_radians;
/**
* 將 degrees 轉成 radians。
*
* @param {Number}degrees
* degrees
* @param {Number}arcminutes
* arcminutes
* @param {Number}arcseconds
* arcseconds
* @param {Boolean}to_days
* 轉成 days (turns)。
*
* @returns {Number}radians
*/
function degrees_to_radians(degrees, arcminutes, arcseconds, to_days) {
if (degrees < 0) {
if (arcminutes)
arcminutes = -arcminutes, arcseconds = -arcseconds;
if (arcseconds)
arcseconds = -arcseconds;
}
return time_to_radians(degrees, arcminutes, arcseconds, to_days, true);
}
_.degrees_to_radians = degrees_to_radians;
/**
* 計算角度差距(減法)。 return (base - target), target 會先趨近於 base。或是說結果會向 0 趨近。
*
* subtract_degrees(base,target)>0: base>target, base-target>0
*
* @param {Object}base
* base coordinates
* @param {Object}target
* target coordinates
*
* @returns {Number}
*/
function subtract_degrees(base, target) {
if (Math.abs(base = (base - target) % TURN_TO_DEGREES)
//
>= TURN_TO_DEGREES / 2)
if (base > 0)
base -= TURN_TO_DEGREES;
else
base += TURN_TO_DEGREES;
return base;
}
/**
* show degrees / sexagesimal system. 顯示易懂角度。
*
* @param {Number}degrees
* degrees
* @param {Integer}padding
* 小數要取的位數。
*
* @returns {String}易懂角度。
*
* @see https://en.wikipedia.org/wiki/Minute_and_second_of_arc
*/
function format_degrees(degree, padding) {
if (!degree)
return '0°';
// is negative.
var minus = degree < 0;
// 處理負數。
if (minus)
degree = -degree;
var value = Math.floor(degree),
//
show = '';
if (value > 0) {
degree -= value;
// 限制範圍在0至360度內。
value %= TURN_TO_DEGREES;
if (padding >= 0 && value < 100)
show = value > 9 ? ' ' : ' ';
show += value + '° ';
}
if (degree > 0) {
value = (degree *= 60) | 0;
if (value || show)
show += (padding && value < 10 ? ' ' : '')
//
+ value + '′ ';
if (degree -= value) {
degree *= 60;
degree = padding >= 0 ? (degree < 10 ? ' ' : '')
+ degree.toFixed(padding) : String(degree);
show += degree.includes('.') ? degree.replace('.', '″.')
// arcseconds
: degree + '″';
}
}
// 處理負數。
if (minus)
show = '-' + show;
return show.replace(/ $/, '');
}
_.format_degrees = format_degrees;
/**
* show time angle. 顯示易懂時角。
*
* @param {Number}days
* days / turns
*
* @returns {String}易懂時角。
*
* @see https://en.wikipedia.org/wiki/Unicode_subscripts_and_superscripts
*/
function days_to_time(days) {
var show = '', minus = days < 0;
// 處理負數。
if (minus)
days = -days;
// time: hours
var time = (days % 1) * ONE_DAY_HOURS;
if (days |= 0)
show += days + 'ᵈ';
days = time | 0;
if (days || show)
show += days + 'ʰ';
// time: minutes
time = (time % 1) * 60;
days = time | 0;
if (days || show)
show += days + 'ᵐ';
// time: seconds
time = (time % 1) * 60;
if (days || show)
show += days + 'ˢ';
// time <= 1e-10: 當作 error。
// 1e-11: -Math.log10((1/2-1/3-1/6)*86400)|0
if ((time %= 1) > 1e-11) {
// 去首尾之 0。
time = time.toPrecision(11).replace(/0+$/, '').replace(/^0+/, '');
if (show)
show += time;
else
show = '0ˢ' + time;
} else if (!show) {
show = '0';
}
// 收尾。
// 處理負數。
if (minus)
show = '-' + show;
return show;
}
_.days_to_time = days_to_time;
/**
* format radians
*
* @param {Number}radians
* radians to format
* @param {String}[to_type]
* to what type: decimal degrees, degrees, time, radians, turns
* @param {Object}[options]
* 附加參數/設定特殊功能與選項:<br />
*
* @returns {String}formatted radians
*/
function format_radians(radians, to_type, options) {
if (!to_type)
// default: degrees of sexagesimal measure
to_type = 'degrees';
switch (to_type) {
case 'decimal':
case 'decimal degrees':
return radians / DEGREES_TO_RADIANS;
case 'degrees':
return format_degrees(radians / DEGREES_TO_RADIANS, options
&& options.padding);
case 'turns':
return radians / TURN_TO_RADIANS;
case 'time':
return days_to_time(radians / TURN_TO_RADIANS);
}
// default
return radians;
}
_.format_radians = format_radians;
// ------------------------------------------------------------------------------------------------------//
// semi-diameter of objects
/**
* 天體的中心視半徑 (in arcseconds)。
*
* e.g., Geocentric semi-diameter of the Sun, apparent radius, 日面的地心視半徑。
*
* Reference 資料來源/資料依據:<br />
* Jean Meeus, Astronomical Algorithms, 2nd Edition. 《天文算法》2版<br />
* p. 390. Chapter 55 Semidiameters of the Sun, Moon, and Planets
*
* @param {Object|Number}coordinates
* coordinates or distance (in AU) of object
* @param {Number|String}[radius]
* object radius (in arcseconds) or object name. default: sun
* @param {Number}[latitude]
* object-centric latitude of the Earth.<br />
* e.g., Saturnicentric latitude of the Earth (see Chapter 45).<br />
* “以土星為中心”的緯度(詳見《天文算法》第45章)。
*
* @returns {Number}semi-diameter (in arcseconds)
*
* @see https://github.com/soniakeys/meeus/blob/master/semidiameter/semidiameter.go
*/
function semidiameter(coordinates, radius, latitude) {
var object = coordinates && coordinates.object
|| (isNaN(radius) ? radius : SUN_NAME);
if (!radius)
radius = object;
if (radius in semidiameter.apparent)
radius = semidiameter.apparent[object = radius];
else if (radius === SUN_NAME)
object = radius, radius = SOLAR_RADIUS_ARCSECONDS;
// assert: radius is in arcseconds now.
var distance = typeof coordinates === 'number' && coordinates > 0 ? coordinates
: coordinates.Δ
|| (object === MOON_NAME ? LUNAR_DISTANCE_M
/ AU_TO_METERS
// 1: default: 1 AU
: 1);
// assert: distance is in AU now.
if (object === MOON_NAME) {
if (false && coordinates.Δ > 0) {
radius = Math.atan(LUNAR_RADIUS_M / AU_TO_METERS
/ coordinates.Δ)
/ ARCSECONDS_TO_RADIANS;
if (latitude)
// → 以觀測者為中心的座標中看到的月亮視半徑
radius += radius * Math.sin(latitude * DEGREES_TO_RADIANS)
* TERRA_RADIUS_M / LUNAR_DISTANCE_M;
return radius;
}
// 設Δ是地球中心到月球中心到的距離(單位是千米),
distance *= AU_TO_METERS / 1000;
/**
* π是月球的赤道地平視差,s是月亮的地心視半徑,k是月亮平均半徑與地球赤道半徑的比值。在1963到1968年的天文曆書中,日月食計算中取k=0.272481
*
* Explanatory Supplement to the Astronomical Ephemeris. Third
* impression 1974.<br />
* p. 213.<br />
* As from 1963, the value of k is taken as 0.2724807, which leads
* to the same value of the semi-diameter as in the lunar ephemeris.
* The value 0.272274 for k is retained, however, in the calculation
* of duration on the central line of total solar eclipses, by way
* of applying an approximate correction for the irregularities of
* the lunar limb.
*
* Explanatory Supplement to the Astronomical Almanac.<br />
* p. 425.<br />
* The lAU adopted a new value of k (k = 0.2725076) in August 1982.
*/
var k = 0.272481, sin_π = 6378.14 / distance;
if (coordinates && coordinates.LHA) {
// p. 280. formula 40.7
var A = Math.cos(coordinates.δ) * Math.sin(coordinates.LHA),
//
B = Math.cos(coordinates.δ) * Math.cos(coordinates.LHA)
- coordinates.ρcos_φp * sin_π,
//
C = Math.sin(coordinates.δ) - coordinates.ρsin_φp * sin_π;
/**
* the topocentric distance of the Moon (that is, the distance
* from the observer to the center of the Moon) is Δ′=q*Δ, q
* being given by formula (40.7).
*/
distance *= Math.sqrt(A * A + B * B + C + C);
sin_π = 6378.14 / distance;
}
radius = Math.asin(k * sin_π) / ARCSECONDS_TO_RADIANS;
} else {
radius /= distance;
if (latitude && object
&& ((object + '_polar') in semidiameter.apparent)) {
// 極半徑/赤道半徑
var k = semidiameter.apparent[object + '_polar']
/ semidiameter.apparent[object];
k = 1 - k * k;
latitude = Math.cos(latitude * DEGREES_TO_RADIANS);
radius *= Math.sqrt(1 - k * latitude * latitude);
}
}
return radius;
}
_.semidiameter = semidiameter;
/**
* apparent radius (arcseconds). 距離 1 AU 時的太陽和行星的視半徑。
*
* @type {Object}
*/
semidiameter.apparent = {
mercury : 3.36,
venus_surface : 8.34,
// +cloud
// 對於金星,值8″.34,指從地球上看它的地殼半徑,而不是指它的雲層。由於這個原因,當計算諸如中天、淩日、星食等天文現象時,我們採用舊值8″.41。
venus : 8.41,
mars : 4.68,
// equatorial
jupiter : 98.44,
jupiter_polar : 92.06,
// equatorial
saturn : 82.73,
saturn_polar : 73.82,
uranus : 35.02,
neptune : 33.50,
pluto : 2.07
};
// ------------------------------------------------------------------------------------------------------//
// coordinate transformations 座標變換
// @see
// https://en.wikipedia.org/wiki/List_of_common_coordinate_transformations
/**
* auto detect time zone. 自動判別時區。
*
* @param {Array}local
* the observer's geographic location [ latitude (°), longitude
* (°), time zone (e.g., UTC+8: 8), elevation or geometric height
* (m) ]<br />
* 觀測者 [ 緯度(北半球為正,南半球為負), 經度(從Greenwich向東為正,西為負), 時區,
* 海拔標高(觀測者距海平面的高度) ]
*
* @returns {Number}time zone. UTC+8: 8
*/
function get_time_zone(local) {
return isNaN(local[2]) ? Math.round(local[1]
/ (TURN_TO_DEGREES / ONE_DAY_HOURS)) : local[2];
}
/**
* 此函數為為了舊曆元所做的修正。
*
* longitude λ must be converted to the ephemeris longitude λ* by increasing
* it by 1.002738 ΔT, the sidereal equivalent of ΔT.
*
* 星曆用的經度從Greenwich向西為正,東為負,與向東為正的一般地理經度用法相反。
*
* Reference 資料來源/資料依據:<br />
* Explanatory Supplement to the Astronomical Ephemeris. Third impression
* 1974.<br />
* p. 241.
*
* The ephemeris meridian is 1.002 738 ΔT east of the Greenwich meridian,
* where ΔT=TT−UT1.
*
* @param {Number}longitude
* longitude of geographic coordinate in degrees, 一般地理經度
* @param {Number}TT_JD
* Julian date (JD of 天文計算用時間 TT)
*
* @returns {Number}ephemeris longitude in radians, 星曆用的經度
*
* @see http://asa.usno.navy.mil/SecM/Glossary.html
*/
function to_ephemeris_longitude(longitude, TT_JD) {
return -longitude * DEGREES_TO_RADIANS;
return ((TT_JD ? 1.002738 * ΔT_of_JD(TT_JD) : 0) - longitude)
* DEGREES_TO_RADIANS;
}
/**
* ephemeris longitude → geographic longitude
*
* @param {Number}longitude
* ephemeris longitude in radians, 星曆用的經度
* @param {Number}TT_JD
* Julian date (JD of 天文計算用時間 TT)
*
* @returns {Number}geographic longitude in degrees
*/
function from_ephemeris_longitude(longitude, TT_JD) {
return normalize_radians(-longitude, true) /
//
DEGREES_TO_RADIANS;
return (TT_JD ? -1.002738 * ΔT_of_JD(TT_JD) : 0) - longitude
/ DEGREES_TO_RADIANS;
}
/**
* 計算角距離 angular distance (in radians)
*
* Reference 資料來源/資料依據:<br />
* Jean Meeus, Astronomical Algorithms, 2nd Edition. 《天文算法》2版<br />
* p. 109. formula 17.1
*
* @param {Object}coordinates_1
* apparent geocentric ecliptical coordinates<br /> { longitude
* α , latitude δ } in radians
* @param {Object}coordinates_2
* apparent geocentric ecliptical coordinates<br /> { longitude
* α , latitude δ } in radians
*
* @returns {Number}angular distance in radians
*/
function angular_distance(coordinates_1, coordinates_2, no_minor_squre) {
var Δα = Math.abs(coordinates_1.α - coordinates_2.α), Δδ,
//
δ1 = coordinates_1.δ, δ2 = coordinates_2.δ;
// 10 / 60 / 360 * (2 * Math.PI) = 0.0029088820866572155
if (!no_minor_squre && Δα < .001 && (Δδ = Math.abs(δ1 - δ2)) < .001) {
// 角度差接近於0或180度時,求取近似值。
Δα *= Math.cos((δ1 + δ2) / 2);
return Math.sqrt(Δα * Δα + Δδ * Δδ);
}
if (false)
console.log(Math.sin(δ1) * Math.sin(δ2) + Math.cos(δ1)
* Math.cos(δ2) * Math.cos(Δα));
return Math.acos(Math.sin(δ1) * Math.sin(δ2) + Math.cos(δ1)
* Math.cos(δ2) * Math.cos(Δα));
}
_.angular_distance = angular_distance;
/**
* 向量長度,與原點距離。
*
* @param {Array}rectangular
* 直角座標 [ x, y, z ]
*
* @returns {Number}distance
*/
function distance_of_rectangular(rectangular) {
var x = rectangular[0], y = rectangular[1], z = rectangular[2];
return Math.sqrt(x * x + y * y + z * z);
}
/**
* spherical coordinates → rectangular coordinates. 球座標系(日心座標)轉為直角座標系。
*
* @param {Number}longitude
* longitude (L) of spherical 球座標
* @param {Number}latitude
* latitude (B) of spherical 球座標
* @param {Number}radius
* radius (R) of spherical 球座標
* @param {Object}[options]
* 附加參數/設定特殊功能與選項:<br />
* {Boolean}options.unit_radius: 若為 true,則將 .R 當作 1。<br />
* {Object}options.base: base spherical coordinates. {L,B,R}
* 基準球座標.
*
* @returns {Object}rectangular coordinates [ x, y, z ]
*
* @see https://en.wikipedia.org/wiki/Ecliptic_coordinate_system#Rectangular_coordinates
* https://en.wikipedia.org/wiki/Equatorial_coordinate_system#Geocentric_equatorial_coordinates
*/
function spherical_to_rectangular(longitude, latitude, radius, options) {
if (library_namespace.is_Object(longitude)) {
options = latitude;
radius = longitude.R;
latitude = longitude.B;
longitude = longitude.L;
}
// 前置處理。
if (!library_namespace.is_Object(options))
options = Object.create(null);
var tmp, cos_B = Math.cos(latitude),
//
x = cos_B * Math.cos(longitude), y = cos_B * Math.sin(longitude), z = Math
.sin(latitude);
if (!options.unit_radius && radius) {
x *= radius;
y *= radius;
z *= radius;
}
if (tmp = options.base) {
tmp = spherical_to_rectangular(tmp, options.unit_radius ? {
unit_radius : true
} : null);
x -= tmp[0];
y -= tmp[1];
z -= tmp[2];
}
tmp = [ x, y, z ];
if (options.distance)
tmp.distance = Math.sqrt(x * x + y * y + z * z);
// return rectangular
return tmp;
}
/**
* rectangular coordinates → spherical coordinates. 直角座標系轉為球座標系(黃道座標)。
*
* Reference 資料來源/資料依據:<br />
* Jean Meeus, Astronomical Algorithms, 2nd Edition. 《天文算法》2版<br />
* p. 223. formula 33.2 座標變換
*
* @param {Array}rectangular
* 直角座標 [ x, y, z ]
* @param {Boolean}get_radius
* 亦生成 radius
*
* @returns {Object}spherical coordinates { λ , β }
*/
function rectangular_to_spherical(rectangular, get_radius) {
var x = rectangular[0], y = rectangular[1], z = rectangular[2],
// ecliptical (or celestial) [ longitude 黃經, latitude 黃緯 ]。
spherical = [ Math.atan2(y, x), Math.atan2(z, Math.sqrt(x * x, y * y)) ];
if (get_radius)
spherical.push(Math.sqrt(x * x + y * y + z * z));
return spherical;
}
/**
* Transformation from ecliptical into equatorial coordinates. G地心視黃道座標轉到
* E地心赤道座標(視赤經及視赤緯)
*
* Reference 資料來源/資料依據:<br />
* Jean Meeus, Astronomical Algorithms, 2nd Edition. 《天文算法》2版<br />
* p. 93. formula 13.3, 13.4
*
* @param {Object}coordinates
* apparent geocentric ecliptical coordinates<br /> { longitude
* λ , latitude β }
* @param {Number}TT_JD
* Julian date (JD of 天文計算用時間 TT)
* @param {Object}[options]
* 附加參數/設定特殊功能與選項
*
* @returns {Object}equatorial coordinates { right ascension α , declination
* δ }
*/
function ecliptical_to_equatorial(coordinates, TT_JD, options) {
var ε = obliquity(TT_JD),
// G地心視黃道 apparent geocentric ecliptic coordinates:
// longitude λ and latitude β in radians
λ = coordinates.λ, β = coordinates.β,
// cache
sin_λ = Math.sin(λ), cos_ε = Math.cos(ε), sin_ε = Math.sin(ε);
// geocentric right ascension 地心赤經。
coordinates.α = Math.atan2(sin_λ * cos_ε - Math.tan(β) * sin_ε, Math
.cos(λ));
// geocentric declination 地心赤緯。
coordinates.δ = Math.asin(Math.sin(β) * cos_ε + Math.cos(β) * sin_ε
* sin_λ);
// 因為 equatorial_to_horizontal() 可能會再利用,這裡不處理 options.degrees。
return coordinates;
}
/**
* equatorial coordinates → local horizontal coordinates.
* 依據觀測者的位置和時間,轉換地心視赤道座標到本地站心地平座標系。
*
* Reference 資料來源/資料依據:<br />
* Jean Meeus, Astronomical Algorithms, 2nd Edition. 《天文算法》2版<br />
* p. 93. formula 13.5, 13.6 座標變換<br />
* Chapter 40: Correction for Parallax
*
* @param {Object}coordinates
* equatorial coordinates { right ascension α , declination δ }
* @param {Number}TT_JD
* Julian date (JD of 天文計算用時間 TT)
* @param {Array}local
* the observer's geographic location [ latitude (°), longitude
* (°), time zone (e.g., UTC+8: 8), elevation or geometric height
* (m) ]<br />
* 觀測者 [ 緯度(北半球為正,南半球為負), 經度(從Greenwich向東為正,西為負), 時區,
* 海拔標高(觀測者距海平面的高度) ]
*
* @returns {Object}horizontal { Alt:altitude (radians) , Az:azimuth
* (radians) }
*
* @see https://en.wikipedia.org/wiki/Horizontal_coordinate_system
*/
function equatorial_to_horizontal(coordinates, TT_JD, local) {
/**
* 地心赤緯δ。
*
* @type {Number}
*/
var δ = coordinates.δ;
if (isNaN(δ))
// 先算出地心視赤道座標。
// 一般已在 function get_horizontal() 中處理。
δ = ecliptical_to_equatorial(coordinates, TT_JD).δ;
/**
* 地心赤經α。
*
* @type {Number}
*/
var α = coordinates.α,
/**
* Phi: lower-case letter φ (or often its variant, ϕ) 觀測者緯度(北半球為正,南半球為負)
*
* @type {Number}
*/
φ = local[0] * DEGREES_TO_RADIANS,
// p. 92.
/**
* Greenwich視恆星時θ0
*
* @type {Number} in radians
*/
θ0 = GAST(TT_of(TT_JD, true), TT_JD),
/**
* 本地恆星時θ = Greenwich視恆星時θ0 - L觀測者星曆經度
*
* @type {Number} in radians
*/
θ = θ0 - to_ephemeris_longitude(local[1], TT_JD),
/**
* local hour angle (in radians)
* 本地地心時角。一個天體的時角是2.5HA,就表示他已經在2.5個小時之前通過當地的子午圈,並且在當地子午圈的西方37.5度的距離上。負數則表示在多少小時之後將通過當地的子午圈。
*
* LHA = 本地恆星時θ − 地心赤經α = Greenwich視恆星時θ0 - L觀測者星曆經度 − 地心赤經α
*
* @type {Number} in radians
*/
LHA = θ - α,
// cache
sin_φ = Math.sin(φ), cos_φ = Math.cos(φ),
// cache
cos_H = Math.cos(LHA),
// p. 82.
// tmp
u = Math.atan(TERRA_POLAR_RADIUS_M / TERRA_EQUATORIAL_RADIUS_M
* Math.tan(φ));
// tmp
LHA /= TERRA_EQUATORIAL_RADIUS_M;
/**
* 計算周日視差、日月食、星蝕所需要的量ρsin(φ′)
*
* @type {Number}
*/
var ρsin_φp = TERRA_POLAR_RADIUS_M / TERRA_EQUATORIAL_RADIUS_M
* Math.sin(u) + LHA * sin_φ,
/**
* 計算周日視差、日月食、星蝕所需要的量ρcos(φ′)
*
* @type {Number}
*/
ρcos_φp = Math.cos(u) + LHA * cos_φ;
coordinates.ρsin_φp = ρsin_φp;
coordinates.ρcos_φp = ρcos_φp;
// p. 279.
// 地心視赤道座標轉到本地站心赤道座標:
// 修正 planet's parallax (行星視差)
var
/**
* the equatorial horizontal parallax of the body in radians. 天體的赤道地平視差.
*
* Math.sin(8.794 * ARCSECONDS_TO_RADIANS) ≈ 0.0000426345
*
* @type {Number} in radians
*/
π = Math.asin(Math.sin(8.794 * ARCSECONDS_TO_RADIANS)
// coordinates.Δ: apparent distance at TT_JD in AU in radians
// 對於太陽、行星和慧星,經常適合使用它們到地球的距離Δ替代視差
/ coordinates.Δ),
// cache
sin_π = Math.sin(π), cos_δ = Math.cos(δ);
coordinates.π = π;
// tmp
u = ρcos_φp * sin_π;
π = cos_δ - u * cos_H;
var Δα = Math.atan2(-u * Math.sin(LHA), π);
// 對於赤緯,不必計算Δδ,用下式可直接算出δ′:
// apply new value to (δ, α, LHA).
δ = Math.atan2((Math.sin(δ) - ρsin_φp * sin_π) * Math.cos(Δα), π);
α += Δα;
// T站心赤道 topocentric equatorial coordinate system
// @see function Coordinates()
coordinates.T = [ α, δ ];
// coordinates.θ0 = θ0;
// coordinates.θ = θ;
// LHA: local hour angle (in radians) 本地地心時角。
coordinates.LHA = LHA = θ - α;
// re-cache
cos_H = Math.cos(LHA);
// p. 93.
// 站心赤道座標轉到站心地平座標 (radians)
// Altitude (Alt) 高度角或仰角又稱地平緯度。
// 修正大氣折射的影響
// TODO: 考慮 dip of the horizon (地平俯角, 海岸視高差)
// @see
// https://en.wikipedia.org/wiki/Horizon#Effect_of_atmospheric_refraction
// http://www-rohan.sdsu.edu/~aty/explain/atmos_refr/altitudes.html
coordinates.Alt = refraction(Math.asin(sin_φ * Math.sin(δ) + cos_φ
* Math.cos(δ) * cos_H)
/ DEGREES_TO_RADIANS)
* DEGREES_TO_RADIANS;
// Azimuth (Az) 方位角又稱地平經度。
coordinates.Az = Math.atan2(Math.sin(LHA), cos_H * sin_φ - Math.tan(δ)
* cos_φ);
// parallactic angle
// https://en.wikipedia.org/wiki/Parallactic_angle
// Jean Meeus, Astronomical Algorithms, 2nd Edition. 《天文算法》2版
// p. 98. formula 14.1
if (false
// 當天體正好在天頂,則沒有定義。
&& (π = Math.tan(φ) * Math.cos(δ) - Math.sin(δ) * cos_H))
coordinates.parallactic = Math.atan2(Math.sin(LHA), π);
// 因為可能會再利用,這裡不處理 options.degrees。
return coordinates;
}
/**
* ecliptical → equatorial coordinates → local horizontal coordinates.
*
* @param {Object}coordinates
* apparent geocentric ecliptical coordinates<br /> { longitude
* λ , latitude β }
* @param {Number}TT_JD
* Julian date (JD of 天文計算用時間 TT)
* @param {Object}[options]
* 附加參數/設定特殊功能與選項
*/
function get_horizontal(coordinates, TT_JD, options) {
var local = Array.isArray(options.local) && options.local;
if (local || options.equatorial) {
// 地心視黃道座標轉到視赤道座標(視赤經及視赤緯)。
ecliptical_to_equatorial(coordinates, TT_JD, options);
// 需要保證有 coordinates.Δ
if (local && coordinates.Δ)
equatorial_to_horizontal(coordinates, TT_JD, local);
// 單位轉換。
if (options.degrees) {
if (local) {
coordinates.Alt /= DEGREES_TO_RADIANS;
coordinates.Az /= DEGREES_TO_RADIANS;
}
coordinates.α /= DEGREES_TO_RADIANS;
coordinates.δ /= DEGREES_TO_RADIANS;
}
}
// elongation Ψ of the planet, its angular distance to the Sun
// https://en.wikipedia.org/wiki/Elongation_%28astronomy%29
// 行星的距角,即地心看行星與太陽的角距離 (angular distance)。
// Jean Meeus, Astronomical Algorithms, 2nd Edition. 《天文算法》2版
// Chapter 48 Illuminated Fraction of the Moon's Disk
if (options.elongation) {
// the Sun's apparent longitude in degrees → radians.
var solar = solar_coordinates(TT_JD, {
equatorial : true
}),
//
λ0 = solar.apparent * DEGREES_TO_RADIANS,
//
cos_Ψ = Math.cos(coordinates.β) * Math.cos(coordinates.λ - λ0);
// The Sun's latitude, which is always smaller than 1.2
// arcsecond, may be neglected here.
// 地心座標下的月球距角ψ
coordinates.Ψ = Math.acos(cos_Ψ);
// 月心座標下的地球距角i
coordinates.i = Math.atan2(solar.Δ * Math.sin(coordinates.Ψ),
coordinates.Δ - solar.Δ * cos_Ψ);
// ψ和i在均在0到180度之間。
// 月亮明亮邊緣的位置角
coordinates.χ = Math.atan2(Math.cos(solar.δ)
* Math.sin(solar.α - coordinates.α), Math.sin(solar.δ)
* Math.cos(coordinates.δ) - Math.cos(solar.δ)
* Math.sin(coordinates.δ)
* Math.cos(solar.α - coordinates.α));
// 單位轉換。
if (options.degrees) {
coordinates.Ψ /= DEGREES_TO_RADIANS;
coordinates.i /= DEGREES_TO_RADIANS;
coordinates.χ /= DEGREES_TO_RADIANS;
}
}
}
// ------------------------------------------------------------------------------------------------------//
// ΔT
/**
* get ΔT of year.<br />
* ΔT = TT - UT<br />
* <br />
* 天文計算/星曆表使用 Terrestrial Time (TT, 地球時標),<br />
* 日常生活中使用 UTC, 接近 Universal Time (UT, 世界時標), 主要為 UT1。<br />
* <br />
* 簡略的說,天文計算用時間 TT = 日常生活時間 UT + ΔT
*
* ΔT is NOT △T
*
* @param {Number}year
* the year value of time = year + (month - 0.5) / 12
* @param {Number}[month]
* the month of time.
*
* @returns {Number} ΔT of year in seconds.
*
* @see https://en.wikipedia.org/wiki/%CE%94T
* @see <a href="http://www.cv.nrao.edu/~rfisher/Ephemerides/times.html"
* accessdate="2015/3/25 20:35">Astronomical Times</a>
* @see http://njsas.org/projects/speed_of_light/roemer/tt-utc.html
*
* @since 2015/3/21 9:23:32
*/
function ΔT(year, month) {
if (month > 0)
year += (month - 0.5) / 12;
var index = 0;
while (true) {
if (year >= ΔT_year_start[index])
break;
if (++index === ΔT_year_start.length) {
// before −500: the same as after 2150.
index = 0;
break;
}
}
var deltaT = polynomial_value(ΔT_coefficients[index],
(year - ΔT_year_base[index]) / 100);
library_namespace.debug('ΔT of year ' + year + ': ' + deltaT
+ ' seconds', 3);
return deltaT;
}
_.deltaT = _.ΔT = ΔT;
/**
* get ΔT of JD.<br />
* ΔT = TT - UT<br />
* <br />
* 天文計算/星曆表使用 Terrestrial Time (TT, 地球時標),<br />
* 日常生活中使用 UTC, 接近 Universal Time (UT, 世界時標), 主要為 UT1。<br />
* <br />
* 簡略的說,天文計算用時間 TT = 日常生活時間 UT + ΔT
*
* @param {Number}JD
* Julian date
*
* @returns {Number} ΔT of year in seconds.
*/
function ΔT_of_JD(JD) {
// + 2000: Julian_century(JD) starts from year 2000.
return ΔT(Julian_century(JD) * 100 + 2000);
}
_.deltaT.JD = ΔT_of_JD;
/**
* get Terrestrial Time of Universal Time JD, apply ΔT to UT.
*
* @param {Number}UT_JD
* Julian date (JD of 日常生活時間 UT)
* @param {Boolean}[TT_to_UT]
* reverse, TT → UT. treat JD as 天文計算用時間 TT.
*
* @returns {Number}JD of TT
*/
function TT_of(UT_JD, TT_to_UT) {
if (library_namespace.is_Date(UT_JD))
UT_JD = library_namespace.Date_to_JD(UT_JD);
var deltaT = ΔT_of_JD(UT_JD) / ONE_DAY_SECONDS;
// normal: UT → TT.
// TT_to_UT: TT → UT.
// 簡略的說,日常生活時間 UT = 天文計算用時間 TT - ΔT
return TT_to_UT ? UT_JD - deltaT : UT_JD + deltaT;
}
/**
* Translate Terrestrial Time JD → Universal Time JD.
*
* @param {Number}TT_JD
* Julian date (JD of 天文計算用時間 TT)
*
* @returns {Number}JD of UT
*/
function UT_of(TT_JD) {
return TT_of(TT_JD, true);
}
_.TT = TT_of;
_.UT = UT_of;
// ------------------------------------------------------------------------------------------------------//
// Atmospheric refraction 大氣折射又稱蒙氣差、折光差(蒙氣即行星的大氣)
/**
* true apparent in degrees ← apparent altitude.<br />
* 大氣折射公式: 真地平緯度 ← 視地平緯度<br />
*
* Reference 資料來源/資料依據:<br />
* Jean Meeus, Astronomical Algorithms, 2nd Edition. 《天文算法》2版<br />
* chapter 大氣折射.<br />
* based on: G. G. Bennett. (1982). "The Calculation of Astronomical
* Refraction in Marine Navigation".
*
* @param {Number}apparent
* apparent altitude in degrees. 視地平緯度/高度角或仰角,單位是度。
* @param {Number}[Celsius]
* temperature in degree Celsius. 攝氏度氣溫
* @param {Number}[pressure]
* pressure in kPa. 地表氣壓
*
* @returns {Number} degrees of true apparent. 單位是度
*
* @since 2015/3/21 21:31:17
*
* @see https://en.wikipedia.org/wiki/Atmospheric_refraction#Calculating_refraction
* @see http://www.astro.com/ftp/swisseph/src/swecl.c
*/
function refraction_to_real(apparent, Celsius, pressure) {
// (86.63175) get 4.186767499821572e-10
// 經測試,再多就變負數。
if (apparent > 86.63175)
// Jean Meeus: 在90°時,不作第二項修正反而更好。
return apparent;
// refraction in arcminutes. 折射角單位是分。
var refraction = 1 / Math.tan((apparent + 7.31 / (apparent + 4.4))
* DEGREES_TO_RADIANS);
// 第二項公式修正
refraction -= 0.06 * Math.sin(14.7 * refraction + 13);
// assert: refraction > 0
// Jean Meeus: 大約修正。折射率還與光的波長有關。這些運算式適用于黃光,它對人眼的靈敏度最高。
// @see
// http://www.iausofa.org/2015_0209_C/sofa/sofa_ast_c.pdf#75
// 常規條件: Both formulas assume an atmospheric pressure
// of 101.0 kPa and a temperature of 10 °C
if (!isNaN(Celsius))
// [K] = [°C] + 273.15
refraction *= (273 + 10) / (273 + refraction);
if (pressure >= 0)
refraction *= pressure / 101;
// 1度 = 60分
return apparent - refraction / 60;
}
/**
* apparent altitude in degrees ← true altitude.<br />
* 大氣折射公式: 視地平緯度 ← 真地平緯度
*
* @param {Number}real
* real altitude in degrees. 真地平緯度/高度角或仰角,單位是度。
* @param {Number}[Celsius]
* temperature in degree Celsius. 攝氏度氣溫
* @param {Number}[pressure]
* pressure in kPa. 地表氣壓
*
* @returns {Number} degrees of apparent altitude. 單位是度
*
* @since 2015/3/21 21:31:17
*
* @see https://en.wikipedia.org/wiki/Atmospheric_refraction#Calculating_refraction
* @see http://www.astro.com/ftp/swisseph/src/swecl.c
*/
function refraction(real, Celsius, pressure) {
// (89.891580) get 2.226931796052203e-10
// 經測試,再多就變負數。
if (real > 89.89158)
// Jean Meeus: h=90°時,該式算得R不等於零。
return real;
// refraction in arcminutes. 折射角單位是分.
var refraction = 1.02 / Math.tan((real + 10.3 / (real + 5.11))
* DEGREES_TO_RADIANS);
// assert: refraction > 0
// Jean Meeus: 大約修正。折射率還與光的波長有關。這些運算式適用于黃光,它對人眼的靈敏度最高。
// 常規條件: Both formulas assume an atmospheric pressure
// of 101.0 kPa and a temperature of 10 °C
if (!isNaN(Celsius))
// [K] = [°C] + 273.15
refraction *= (273 + 10) / (273 + refraction);
if (pressure >= 0)
refraction *= pressure / 101;
// 1度 = 60分
return real + refraction / 60;
}
refraction.to_real = refraction_to_real;
_.refraction = refraction;
// ------------------------------------------------------------------------------------------------------//
// obliquity 轉軸傾角。
/**
* 地球的平均轉軸傾角,平黃赤交角。 get mean obliquity of the ecliptic (Earth's axial tilt),
* IAU 2006 precession model.
*
* Reference 資料來源/資料依據:
* https://github.com/kanasimi/IAU-SOFA/blob/master/src/obl06.c
*
* @param {Number}TT_JD
* Julian date (JD of 天文計算用時間 TT)
*
* @returns {Number} obliquity in radians
*/
function mean_obliquity_IAU2006(TT_JD) {
return polynomial_value(IAU2006_obliquity_coefficients,
// Interval between fundamental date J2000.0
// and given date (JC).
Julian_century(TT_JD)) * ARCSECONDS_TO_RADIANS;
}
/**
* 地球的平均轉軸傾角,平黃赤交角。 get mean obliquity of the ecliptic (Earth's axial tilt).
*
* Reference 資料來源/資料依據: Laskar, J. (1986). "Secular Terms of Classical
* Planetary Theories Using the Results of General Relativity".
*
* J. Laskar computed an expression to order T10 good to 0″.02 over 1000
* years and several arcseconds over 10,000 years.
*
* @param {Number}TT_JD
* Julian date (JD of 天文計算用時間 TT), 適用於J2000.0起算前後各10000年的範圍內。
*
* @returns {Number} obliquity in radians
*/
function mean_obliquity_Laskar(TT_JD) {
return polynomial_value(Laskar_obliquity_coefficients,
// J2000.0 起算的儒略萬年數
Julian_century(TT_JD) / 100) * DEGREES_TO_RADIANS;
}
/**
* 地球的平均轉軸傾角,平黃赤交角。
*
* @type {Function}
*/
var mean_obliquity = mean_obliquity_Laskar;
/**
* 地球的轉軸傾角,真黃赤交角ε。<br />
* get obliquity of the ecliptic (Earth's axial tilt).
*
* @param {Number}TT_JD
* Julian date (JD of 天文計算用時間 TT)
*
* @returns {Number}obliquity in radians
*
* @see https://en.wikipedia.org/wiki/Axial_tilt
*/
function obliquity(TT_JD) {
// 真黃赤交角是ε=ε0+Δε,Δε是交角章動。(詳見第21章 章動及黃赤交角)。
return mean_obliquity(TT_JD) + nutation(TT_JD)[1];
}
_.obliquity = obliquity;
// ------------------------------------------------------------------------------------------------------//
// sidereal time. 恆星時
/**
* Earth rotation angle (IAU 2000 model). 地球自轉角
*
* Reference 資料來源/資料依據:<br />
* IAU-SOFA: /src/era00.c
*
* @param {Number}UT_JD
* Julian date (JD of 日常生活時間 UT)
*
* @returns {Number}Earth rotation angle (radians)
*
* @see https://github.com/kanasimi/IAU-SOFA/blob/master/src/era00.c
*/
function IAU2000_ERA(UT_JD) {
return TURN_TO_RADIANS * (
// Fractional part of T (days).
(UT_JD % 1)
// Astronomical Almanac 2011:
// Earth rotation angle (ERA) at J2000.0 UT1:
// theta_0 = 0.7790572732640 revolutions
+ 0.7790572732640
// Astronomical Almanac 2011:
// Rate of advance of ERA:
// d(theta)/dUT1 = 1.00273781191135448 revs/UT1-day
+ 0.00273781191135448
// Days since fundamental epoch.
* (UT_JD - J2000_epoch));
}
/**
* Earth rotation angle. 地球自轉角
*
* @type {Function}
*/
_.ERA = IAU2000_ERA;
/**
* terms for function IAU2006_GMST()
*
* Reference 資料來源/資料依據:<br />
* IAU-SOFA: /src/gmst06.c
*
* @type {Array}
* @inner
*
* @see https://github.com/kanasimi/IAU-SOFA/blob/master/src/gmst06.c
*/
var IAU2006_GMST_parameters = [ 0.014506, 4612.156534, 1.3915817,
-0.00000044, -0.000029956, -0.0000000368 ].map(function(p) {
return p * ARCSECONDS_TO_RADIANS;
});
/**
* Greenwich mean sidereal time (consistent with IAU 2006 precession).
*
* Both UT1 and TT are required, UT1 to predict the Earth rotation and TT to
* predict the effects of precession.
*
* his GMST is compatible with the IAU 2006 precession and must not be used
* with other precession models.
*
* Reference 資料來源/資料依據:<br />
* IAU-SOFA: /src/gmst06.c
*
* @param {Number}UT_JD
* Julian date (JD of 日常生活時間 UT)
* @param {Number}TT_JD
* Julian date (JD of 天文計算用時間 TT)
*
* @returns {Number}Greenwich mean sidereal time (radians)
*
* @see https://github.com/kanasimi/IAU-SOFA/blob/master/src/gmst06.c
*/
function IAU2006_GMST(UT_JD, TT_JD) {
if (isNaN(TT_JD))
TT_JD = TT_of(UT_JD);
/**
* Julian centuries since J2000.0.<br />
* J2000.0 起算的儒略世紀數.
*
* @type {Number}
*/
var T = Julian_century(TT_JD);
// Greenwich mean sidereal time, IAU 2006.
return IAU2000_ERA(UT_JD)
+ polynomial_value(IAU2006_GMST_parameters, T);
}
/**
* terms for function Meeus_GMST()
*
* Reference 資料來源/資料依據:<br />
* Jean Meeus, Astronomical Algorithms, 2nd Edition. 《天文算法》2版<br />
* p. 88. formula 12.4
*
* @type {Array}
* @inner
*/
var Meeus_GMST_parameters = [ 280.46061837,
360.98564736629 * DAYS_OF_JULIAN_CENTURY, 0.000387933,
-1 / 38710000 ].map(function(p) {
return p * DEGREES_TO_RADIANS;
});
/**
* The mean sidereal time at Greenwich at Oh UT
*
* Reference 資料來源/資料依據:<br />
* Jean Meeus, Astronomical Algorithms, 2nd Edition. 《天文算法》2版<br />
* p. 88. formula 12.4
*
* @param {Number}UT_JD
* Julian date (JD of 日常生活時間 UT)
*
* @returns {Number}Greenwich mean sidereal time (radians)
*/
function Meeus_GMST(UT_JD) {
/**
* Julian centuries since J2000.0.<br />
* J2000.0 起算的儒略世紀數.
*
* @type {Number}
*/
var T = Julian_century(UT_JD);
return polynomial_value(Meeus_GMST_parameters, T).mod(TURN_TO_RADIANS);
}
/**
* Greenwich mean sidereal time. 平恆星時
*
* @type {Function}
*/
var GMST = IAU2006_GMST;
_.GMST = GMST;
/**
* Greenwich apparent sidereal time, IAU 2006. G