UNPKG

cejs

Version:

A JavaScript module framework that is simple to use.

1,770 lines (1,634 loc) 267 kB
/** * @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