when_exe 0.2.100 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (193) hide show
  1. data/LICENSE.ja.txt +25 -25
  2. data/LICENSE.txt +31 -31
  3. data/bin/irb.rc +5 -0
  4. data/bin/locales.rb +2 -2
  5. data/bin/when.rb +16 -0
  6. data/bin/when.rb.config +7 -0
  7. data/lib/when_exe.rb +616 -14
  8. data/lib/when_exe/basictypes.rb +615 -0
  9. data/lib/when_exe/calendartypes.rb +1700 -0
  10. data/lib/when_exe/coordinates.rb +1936 -0
  11. data/lib/when_exe/core/compatibility.rb +54 -0
  12. data/lib/when_exe/core/duration.rb +72 -72
  13. data/lib/when_exe/core/extension.rb +382 -0
  14. data/lib/when_exe/ephemeris.rb +1845 -0
  15. data/lib/when_exe/googlecalendar.rb +140 -0
  16. data/lib/when_exe/icalendar.rb +1587 -0
  17. data/lib/when_exe/inspect.rb +1237 -0
  18. data/lib/when_exe/locales/af.rb +90 -0
  19. data/lib/when_exe/locales/ar.rb +145 -0
  20. data/lib/when_exe/locales/az.rb +90 -0
  21. data/lib/when_exe/locales/bg.rb +90 -0
  22. data/lib/when_exe/locales/bn.rb +94 -0
  23. data/lib/when_exe/locales/bs.rb +121 -0
  24. data/lib/when_exe/locales/ca.rb +92 -0
  25. data/lib/when_exe/locales/cs.rb +107 -0
  26. data/lib/when_exe/locales/cy.rb +150 -0
  27. data/lib/when_exe/locales/da.rb +84 -0
  28. data/lib/when_exe/locales/de.rb +92 -0
  29. data/lib/when_exe/locales/de_AT.rb +92 -0
  30. data/lib/when_exe/locales/de_CH.rb +92 -0
  31. data/lib/when_exe/locales/el.rb +93 -0
  32. data/lib/when_exe/locales/en.rb +88 -0
  33. data/lib/when_exe/locales/en_AU.rb +88 -0
  34. data/lib/when_exe/locales/en_CA.rb +88 -0
  35. data/lib/when_exe/locales/en_GB.rb +88 -0
  36. data/lib/when_exe/locales/en_IN.rb +88 -0
  37. data/lib/when_exe/locales/en_NZ.rb +88 -0
  38. data/lib/when_exe/locales/eo.rb +89 -0
  39. data/lib/when_exe/locales/es.rb +84 -0
  40. data/lib/when_exe/locales/es_419.rb +84 -0
  41. data/lib/when_exe/locales/es_AR.rb +84 -0
  42. data/lib/when_exe/locales/es_CL.rb +84 -0
  43. data/lib/when_exe/locales/es_CO.rb +84 -0
  44. data/lib/when_exe/locales/es_MX.rb +84 -0
  45. data/lib/when_exe/locales/es_PE.rb +85 -0
  46. data/lib/when_exe/locales/es_VE.rb +84 -0
  47. data/lib/when_exe/locales/et.rb +94 -0
  48. data/lib/when_exe/locales/eu.rb +95 -0
  49. data/lib/when_exe/locales/fa.rb +80 -0
  50. data/lib/when_exe/locales/fi.rb +89 -0
  51. data/lib/when_exe/locales/fr.rb +88 -0
  52. data/lib/when_exe/locales/fr_CA.rb +88 -0
  53. data/lib/when_exe/locales/fr_CH.rb +88 -0
  54. data/lib/when_exe/locales/gl.rb +81 -0
  55. data/lib/when_exe/locales/he.rb +84 -0
  56. data/lib/when_exe/locales/hi.rb +80 -0
  57. data/lib/when_exe/locales/hi_IN.rb +84 -0
  58. data/lib/when_exe/locales/hr.rb +128 -0
  59. data/lib/when_exe/locales/hu.rb +84 -0
  60. data/lib/when_exe/locales/id.rb +89 -0
  61. data/lib/when_exe/locales/is.rb +89 -0
  62. data/lib/when_exe/locales/it.rb +87 -0
  63. data/lib/when_exe/locales/it_CH.rb +87 -0
  64. data/lib/when_exe/locales/ja.rb +78 -0
  65. data/lib/when_exe/locales/kn.rb +86 -0
  66. data/lib/when_exe/locales/ko.rb +78 -0
  67. data/lib/when_exe/locales/links.rb +2342 -0
  68. data/lib/when_exe/locales/lo.rb +123 -0
  69. data/lib/when_exe/locales/locales.rb +91 -0
  70. data/lib/when_exe/locales/lt.rb +111 -0
  71. data/lib/when_exe/locales/lv.rb +118 -0
  72. data/lib/when_exe/locales/mk.rb +93 -0
  73. data/lib/when_exe/locales/mn.rb +80 -0
  74. data/lib/when_exe/locales/nb.rb +81 -0
  75. data/lib/when_exe/locales/ne.rb +81 -0
  76. data/lib/when_exe/locales/nl.rb +92 -0
  77. data/lib/when_exe/locales/nn.rb +73 -0
  78. data/lib/when_exe/locales/or.rb +84 -0
  79. data/lib/when_exe/locales/pl.rb +128 -0
  80. data/lib/when_exe/locales/pt.rb +88 -0
  81. data/lib/when_exe/locales/pt_BR.rb +88 -0
  82. data/lib/when_exe/locales/rm.rb +143 -0
  83. data/lib/when_exe/locales/ro.rb +105 -0
  84. data/lib/when_exe/locales/ru.rb +128 -0
  85. data/lib/when_exe/locales/sk.rb +109 -0
  86. data/lib/when_exe/locales/sl.rb +122 -0
  87. data/lib/when_exe/locales/sr.rb +122 -0
  88. data/lib/when_exe/locales/sv.rb +83 -0
  89. data/lib/when_exe/locales/sw.rb +89 -0
  90. data/lib/when_exe/locales/th.rb +78 -0
  91. data/lib/when_exe/locales/tl.rb +99 -0
  92. data/lib/when_exe/locales/tr.rb +96 -0
  93. data/lib/when_exe/locales/uk.rb +128 -0
  94. data/lib/when_exe/locales/uz.rb +128 -0
  95. data/lib/when_exe/locales/vi.rb +94 -0
  96. data/lib/when_exe/locales/wo.rb +82 -0
  97. data/lib/when_exe/locales/zh_CN.rb +77 -0
  98. data/lib/when_exe/locales/zh_HK.rb +77 -0
  99. data/lib/when_exe/locales/zh_TW.rb +77 -0
  100. data/lib/when_exe/mini_application.rb +252 -0
  101. data/lib/when_exe/parts/enumerator.rb +472 -0
  102. data/lib/when_exe/parts/geometric_complex.rb +379 -0
  103. data/lib/when_exe/parts/locale.rb +513 -0
  104. data/lib/when_exe/parts/method_cash.rb +207 -0
  105. data/lib/when_exe/parts/resource.rb +806 -0
  106. data/lib/when_exe/parts/timezone.rb +182 -0
  107. data/lib/when_exe/region/bahai.rb +145 -0
  108. data/lib/when_exe/region/balinese.rb +627 -0
  109. data/lib/when_exe/region/chinese.rb +896 -0
  110. data/lib/when_exe/region/chinese_calendar.rb +919 -0
  111. data/lib/when_exe/region/chinese_epoch.rb +1245 -0
  112. data/lib/when_exe/region/christian.rb +644 -0
  113. data/lib/when_exe/region/far_east.rb +192 -0
  114. data/lib/when_exe/region/french.rb +66 -0
  115. data/lib/when_exe/region/geologicalage.rb +639 -0
  116. data/lib/when_exe/region/indian.rb +1066 -0
  117. data/lib/when_exe/region/iranian.rb +66 -0
  118. data/lib/when_exe/region/islamic.rb +105 -0
  119. data/lib/when_exe/region/japanese.rb +851 -0
  120. data/lib/when_exe/region/japanese_notes.rb +964 -0
  121. data/lib/when_exe/region/japanese_residues.rb +1149 -0
  122. data/lib/when_exe/region/javanese.rb +228 -0
  123. data/lib/when_exe/region/jewish.rb +127 -0
  124. data/lib/when_exe/region/korean.rb +267 -0
  125. data/lib/when_exe/region/m17n.rb +115 -0
  126. data/lib/when_exe/region/martian.rb +215 -0
  127. data/lib/when_exe/region/mayan.rb +122 -0
  128. data/lib/when_exe/region/moon.rb +333 -0
  129. data/lib/when_exe/region/nihon_shoki.rb +73 -0
  130. data/lib/when_exe/region/planets.rb +585 -0
  131. data/lib/when_exe/region/pope.rb +298 -0
  132. data/lib/when_exe/region/residue.rb +229 -0
  133. data/lib/when_exe/region/roman.rb +325 -0
  134. data/lib/when_exe/region/ryukyu.rb +98 -0
  135. data/lib/when_exe/region/shire.rb +254 -0
  136. data/lib/when_exe/region/sun.rb +210 -0
  137. data/lib/when_exe/region/thai.rb +227 -0
  138. data/lib/when_exe/region/tibetan.rb +233 -0
  139. data/lib/when_exe/region/v50.rb +111 -0
  140. data/lib/when_exe/region/vietnamese.rb +173 -0
  141. data/lib/when_exe/region/world.rb +197 -0
  142. data/lib/when_exe/timestandard.rb +547 -0
  143. data/lib/when_exe/tmduration.rb +330 -330
  144. data/lib/when_exe/tmobjects.rb +1295 -0
  145. data/lib/when_exe/tmposition.rb +1955 -0
  146. data/lib/when_exe/tmreference.rb +1547 -0
  147. data/lib/when_exe/version.rb +10 -3
  148. data/link_to_online_documents +4 -0
  149. data/test/examples/JapanHolidays.ics +456 -0
  150. data/test/examples/Millennium.ics +17 -0
  151. data/test/examples/NewYork.ics +61 -0
  152. data/test/examples/Residue.m17n +135 -0
  153. data/test/examples/Spatial.m17n +179 -0
  154. data/test/examples/Terms.m17n +39 -0
  155. data/test/examples/Test.ics +53 -0
  156. data/test/examples/USA-DST.ics +61 -0
  157. data/test/examples/geometric_complex.rb +41 -0
  158. data/test/examples/sample.xml +14 -0
  159. data/test/examples/today.rb +61 -0
  160. data/test/test.rb +54 -19
  161. data/test/test.rb.config +1 -0
  162. data/test/test/basictypes.rb +368 -0
  163. data/test/test/calendartypes.rb +57 -0
  164. data/test/test/coordinates.rb +380 -0
  165. data/test/test/ephemeris.rb +127 -0
  166. data/test/test/googlecalendar.rb +167 -0
  167. data/test/test/icalendar.rb +848 -0
  168. data/test/test/inspect.rb +115 -0
  169. data/test/test/parts.rb +480 -0
  170. data/test/test/region/chinese.rb +161 -0
  171. data/test/test/region/french.rb +33 -0
  172. data/test/test/region/geologicalage.rb +14 -0
  173. data/test/test/region/indian.rb +55 -0
  174. data/test/test/region/iran.rb +54 -0
  175. data/test/test/region/islamic.rb +18 -0
  176. data/test/test/region/japanese.rb +62 -0
  177. data/test/test/region/jewish.rb +61 -0
  178. data/test/test/region/m17n.rb +181 -0
  179. data/test/test/region/mayan.rb +78 -0
  180. data/test/test/region/moon.rb +14 -0
  181. data/test/test/region/planets.rb +14 -0
  182. data/test/test/region/residue.rb +123 -0
  183. data/test/test/region/sun.rb +14 -0
  184. data/test/test/region/thai.rb +94 -0
  185. data/test/test/region/tibetan.rb +30 -0
  186. data/test/test/tmobjects.rb +356 -57
  187. data/test/test/tmposition.rb +237 -0
  188. data/test/test/tmreference.rb +95 -0
  189. data/when_exe.gemspec +2 -2
  190. metadata +187 -7
  191. data/doc/COPYING +0 -31
  192. data/doc/COPYING.ja +0 -25
  193. data/doc/document_url +0 -1
@@ -0,0 +1,1845 @@
1
+ # -*- coding: utf-8 -*-
2
+ =begin
3
+ Copyright (C) 2011-2013 Takashi SUGA
4
+
5
+ You may use and/or modify this file according to the license described in the LICENSE.txt file included in this archive.
6
+ =end
7
+
8
+ #
9
+ # 天体の位置計算用モジュール
10
+ #
11
+ module When::Ephemeris
12
+
13
+ autoload :Sun, 'when_exe/region/sun'
14
+ autoload :Mercury, 'when_exe/region/planets'
15
+ autoload :Venus, 'when_exe/region/planets'
16
+ autoload :Earth, 'when_exe/region/sun'
17
+ autoload :JGD2000, 'when_exe/region/sun'
18
+ autoload :Mars, 'when_exe/region/planets'
19
+ autoload :Jupiter, 'when_exe/region/planets'
20
+ autoload :Saturn, 'when_exe/region/planets'
21
+ autoload :Uranus, 'when_exe/region/planets'
22
+ autoload :Neptune, 'when_exe/region/planets'
23
+ autoload :Pluto, 'when_exe/region/planets'
24
+ autoload :Moon, 'when_exe/region/moon'
25
+ autoload :Shadow, 'when_exe/region/moon'
26
+ autoload :V50, 'when_exe/region/v50'
27
+ autoload :Hindu, 'when_exe/region/indian'
28
+
29
+ include Math
30
+
31
+ DAY = 86400.0 # 日 / 秒
32
+ BCENT = 36524.2194 # ベッセル世紀
33
+ JCENT = 36525.0 # ユリウス世紀
34
+ JYEAR = JCENT/100 # ユリウス年
35
+ EPOCH1800 = 2378496.0 # 1800 I 0.5
36
+ EPOCH1900 = 2415021.0 # 1900 I 1.5
37
+ EPOCH1975 = 2442412.5 # 1975 I 0.0
38
+ EPOCH2000 = 2451545.0 # 2000 I 1.5
39
+
40
+ DEG = PI / 180 # 度 / radian
41
+ CIRCLE = 2 * PI # 全円周 / radian
42
+ AU = 1.49597870E8 # 天文単位距離 / km
43
+ C0 = 299792.458*86400*JCENT # 光速度 / (km/ユリウス世紀)
44
+ PSEC = 360.0*60.0*60.0/(2*PI) # パーセク / AU
45
+ FARAWAY = 10000.0 * PSEC # 遠距離物体のための仮定義
46
+
47
+ # 演算の番号
48
+ LIN = -1
49
+ SIN = 0
50
+ COS = 1
51
+ SINT = 2
52
+ COST = 3
53
+ SINL = 4
54
+ COSL = 5
55
+ SINLT = 6
56
+ COSLT = 7
57
+ AcS = 8
58
+
59
+ module_function
60
+
61
+ #
62
+ # 多項式
63
+ #
64
+ # @param [Numeric] t 独立変数
65
+ # @param [Array<Numeric>] equ 係数の Array
66
+ #
67
+ # @return [Numeric]
68
+ #
69
+ def polynomial(t, equ)
70
+ equ.reverse.inject(0) {|sum, v| sum * t + v}
71
+ end
72
+
73
+ #
74
+ # 三角関数の和
75
+ #
76
+ # @param [Numeric] t 独立変数
77
+ # @param [Array<Numeric>] equ 係数の Array
78
+ # @param [Numeric] dl 位相補正値(デフォルト 補正なし)
79
+ # @param [Integer] count 打ち切り項数(デフォルト 打ち切りなし)
80
+ #
81
+ # @return [Numeric]
82
+ #
83
+ def trigonometric(t, equ, dl=0.0, count=0)
84
+ t2 = t * t
85
+ equ[0..(count-1)].inject(0) do |sum, v|
86
+ op, epoch, freq, amp, sqr = v
87
+ ds = epoch + t * freq
88
+ if (op < 0) # 直線
89
+ ds += t2 * amp
90
+ else # 三角関数
91
+ ds += t2 * sqr if sqr
92
+ ds += dl if (op[2]==1) # delta L is exist
93
+ ds = amp * ((op[0]==1) ? cosd(ds) : sind(ds))
94
+ ds *= t if (op[1]==1) # time proportional
95
+ end
96
+ sum += ds
97
+ end
98
+ end
99
+
100
+ # arc sin / radian
101
+ # @param [Numeric] x 独立変数
102
+ # @return [Numeric]
103
+ def asin(x)
104
+ atan2(x, sqrt(1-x*x))
105
+ end
106
+
107
+ # arc cos / radian
108
+ # @param [Numeric] x 独立変数
109
+ # @return [Numeric]
110
+ def acos(x)
111
+ atan2(sqrt(1-x*x), x)
112
+ end
113
+
114
+ # 度のcos
115
+ # @param [Numeric] x 独立変数
116
+ # @return [Numeric]
117
+ def cosd(x)
118
+ cos(x * DEG)
119
+ end
120
+
121
+ # 度のsin
122
+ # @param [Numeric] x 独立変数
123
+ # @return [Numeric]
124
+ def sind(x)
125
+ sin(x * DEG)
126
+ end
127
+
128
+ # 度のtan
129
+ # @param [Numeric] x 独立変数
130
+ # @return [Numeric]
131
+ def tand(x)
132
+ tan(x * DEG)
133
+ end
134
+
135
+ # 円周単位のcos
136
+ # @param [Numeric] x 独立変数
137
+ # @return [Numeric]
138
+ def cosc(x)
139
+ cos(x * CIRCLE)
140
+ end
141
+
142
+ # 円周単位のsin
143
+ # @param [Numeric] x 独立変数
144
+ # @return [Numeric]
145
+ def sinc(x)
146
+ sin(x * CIRCLE)
147
+ end
148
+
149
+ # 円周単位のtan
150
+ # @param [Numeric] x 独立変数
151
+ # @return [Numeric]
152
+ def tanc(x)
153
+ tan(x * CIRCLE)
154
+ end
155
+
156
+ #
157
+ # 極座標→直交座標(3次元)
158
+ #
159
+ # @param [Numeric] phi 経度 / CIRCLE
160
+ # @param [Numeric] theta 緯度 / CIRCLE
161
+ # @param [Numeric] radius 距離
162
+ #
163
+ # @return [Array<Numeric>] ( x, y, z )
164
+ # [ x - x 座標 ]
165
+ # [ y - y 座標 ]
166
+ # [ z - z 座標 ]
167
+ #
168
+ def _to_r3(phi, theta, radius)
169
+ c, s = cosc(theta), sinc(theta)
170
+ return [radius*c*cosc(phi), radius*c*sinc(phi), radius*s]
171
+ end
172
+
173
+ #
174
+ # 直交座標→極座標(3次元)
175
+ #
176
+ # @param [Numeric] x x 座標
177
+ # @param [Numeric] y y 座標
178
+ # @param [Numeric] z z 座標
179
+ #
180
+ # @return [Array<Numeric>] ( phi, theta, radius )
181
+ # [ phi - 経度 / CIRCLE ]
182
+ # [ theta - 緯度 / CIRCLE ]
183
+ # [ radius - 距離 ]
184
+ #
185
+ def _to_p3(x, y, z)
186
+ phi, radius = _to_p2(x, y)
187
+ theta, radius = _to_p2(radius, z)
188
+ return [phi, theta, radius]
189
+ end
190
+
191
+ #
192
+ # 直交座標→極座標(2次元)
193
+ #
194
+ # @param [Numeric] x x 座標
195
+ # @param [Numeric] y y 座標
196
+ #
197
+ # @return [Array<Numeric>] ( phi, radius )
198
+ # [ phi - 経度 / CIRCLE ]
199
+ # [ radius - 距離 ]
200
+ #
201
+ def _to_p2(x, y)
202
+ return [0.0, 0.0] if x==0 && y==0
203
+ return [atan2(y,x)/CIRCLE, sqrt(x*x+y*y)]
204
+ end
205
+
206
+ #
207
+ # 回転(2次元)
208
+ #
209
+ # @param [Numeric] x x 座標
210
+ # @param [Numeric] y y 座標
211
+ # @param [Numeric] t 回転角 / CIRCLE
212
+ #
213
+ # @return [Array<Numeric>] ( x, y )
214
+ # [ x - x 座標 ]
215
+ # [ y - y 座標 ]
216
+ #
217
+ def _rot(x, y, t)
218
+ c, s = cosc(t), sinc(t)
219
+ return [x*c - y*s, x*s + y*c]
220
+ end
221
+
222
+ # 時間の単位の換算 - 1975年元期の dynamical_time / ユリウス年
223
+ #
224
+ # @param [Numeric] tt ユリウス日(Terrestrial Time)
225
+ #
226
+ # @return [Numeric]
227
+ #
228
+ def julian_year_from_1975(tt)
229
+ return (tt - EPOCH1975) / JYEAR
230
+ end
231
+
232
+ # 時間の単位の換算 - 2000年元期の dynamical_time / ユリウス世紀
233
+ #
234
+ # @param [Numeric] tt ユリウス日(Terrestrial Time)
235
+ #
236
+ # @return [Numeric]
237
+ #
238
+ def julian_century_from_2000(tt)
239
+ return (tt - EPOCH2000) / JCENT
240
+ end
241
+
242
+ # Δε
243
+ #
244
+ # @param [Numeric] c 2000年からの経過世紀
245
+ #
246
+ # @return [Numeric] 緯度の章動 / CIRCLE
247
+ #
248
+ def delta_e(c)
249
+ trigonometric(c,
250
+ [[COS , 125.04 , -1934.136 , +0.00256 ],
251
+ [COS , 200.93 , +72001.539 , +0.00016 ]]) / 360
252
+ end
253
+ alias :deltaE :delta_e
254
+
255
+ # Δφ
256
+ #
257
+ # @param [Numeric] c 2000年からの経過世紀
258
+ #
259
+ # @return [Numeric] 経度の章動 / CIRCLE
260
+ #
261
+ def delta_p(c)
262
+ trigonometric(c,
263
+ [[SIN , 125.04 , -1934.136 , -0.00478 ],
264
+ [SIN , 200.93 , +72001.539 , +0.00037 ]]) / 360
265
+ end
266
+ alias :deltaP :delta_p
267
+
268
+ # 黄道傾角
269
+ #
270
+ # @param [Numeric] c 2000年からの経過世紀
271
+ #
272
+ # @return [Numeric] 黄道傾角 / CIRCLE
273
+ #
274
+ def obl(c)
275
+ return (23.43929 + -0.013004*c + 1.0*delta_e(c)) / 360
276
+ end
277
+
278
+ # func の逆変換
279
+ #
280
+ # @param [Numeric] t0 独立変数の初期近似値
281
+ # @param [Numeric] y0 逆変換される関数値(nil なら極値を求める)
282
+ # @param [Block] func 逆変換される関数
283
+ #
284
+ # @return [Numeric] 逆変換結果
285
+ #
286
+ def root(t0, y0=nil, &func)
287
+
288
+ # 近似値0,1
289
+ # printf("y0=%20.7f\n",y0)
290
+ t = [t0, t0+0.1 ]
291
+ y = [func.call(t[0]), func.call(t[1])]
292
+ # printf("t=%20.7f,L=%20.7f\n",t[1],y[1])
293
+
294
+ # 近似値2(1次関数による近似)
295
+ t << (y0 ? (t[1]-t[0])/(y[1]-y[0])*(y0-y[0])+t[0] : t0-0.1)
296
+
297
+ # 繰り返し
298
+ i = 10
299
+ while ((t[2]-t[1]).abs > 1E-6) && (i > 0)
300
+ # 予備計算
301
+ y << func.call(t[2])
302
+ break if y0 && (y[2]-y0).abs <= 1E-7
303
+
304
+ # printf("t=%20.7f,L=%20.7f\n",t[2],y[2])
305
+ t01 = t[0]-t[1]
306
+ t02,y02 = t[0]-t[2], y[0]-y[2]
307
+ t12,y12 = t[1]-t[2], y[1]-y[2]
308
+
309
+ # 2次関数の係数
310
+ a = ( y02 / t02 - y12 / t12) / t01
311
+ b = (-y02*t12 / t02 + y12*t02 / t12) / t01
312
+ c = y[2]
313
+
314
+ if y0
315
+ # 判別式
316
+ if (d = b*b-4*a*(c-y0)) < 0
317
+ i = -1
318
+ break
319
+ end
320
+
321
+ # 近似値(2次関数による近似)
322
+ sqrtd = Math.sqrt(d)
323
+ sqrtd = -sqrtd if b < 0
324
+ t << (t[2] + 2*(y0-c)/(b+sqrtd)) # <-桁落ち回避
325
+ else
326
+ t << (t[2] - b / (2*a))
327
+ end
328
+
329
+ t.shift
330
+ y.shift
331
+ end
332
+ $stderr.puts "The result is not reliable" if i<=0
333
+ return t[2]
334
+ end
335
+
336
+ #
337
+ # 天体の座標
338
+ #
339
+ class Coords
340
+
341
+ include When::Ephemeris
342
+
343
+ class << self
344
+ alias :polar :new
345
+
346
+ # オブジェクトの生成
347
+ #
348
+ # @param [Numeric] x x 座標
349
+ # @param [Numeric] y y 座標
350
+ # @param [Numeric] z z 座標
351
+ # @param [Numeric] c 周回数(デフォルト - phi から生成)
352
+ #
353
+ # 極座標との1対1対応を保証するため、z軸の周りを何週して
354
+ # 現在の位置にあるかを保持する
355
+ #
356
+ # @return [When::Ephemeris::Coords]
357
+ #
358
+ def rectangular(x, y, z, c=nil)
359
+ Coords.new(x, y, z, c, {:system=>:rectangular})
360
+ end
361
+ end
362
+
363
+ # 直交座標
364
+ #
365
+ # @return [Array<Numeric>] ( x, y, z )
366
+ # [ x - x 座標 ]
367
+ # [ y - y 座標 ]
368
+ # [ z - z 座標 ]
369
+ #
370
+ def rectangular
371
+ @x, @y, @z = _to_r3(@phi, @theta, @radius) unless @z
372
+ return [@x, @y, @z]
373
+ end
374
+
375
+ # x 座標
376
+ #
377
+ # @return [Numeric]
378
+ #
379
+ def x ; @x || rectangular[0] ; end
380
+
381
+ # y 座標
382
+ #
383
+ # @return [Numeric]
384
+ #
385
+ def y ; @y || rectangular[1] ; end
386
+
387
+ # z 座標
388
+ #
389
+ # @return [Numeric]
390
+ #
391
+ def z ; @z || rectangular[2] ; end
392
+
393
+ # 極座標
394
+ #
395
+ # @return [Array<Numeric>] ( phi, theta, radius, c )
396
+ # [ phi - 経度 / CIRCLE ]
397
+ # [ theta - 緯度 / CIRCLE ]
398
+ # [ radius - 距離 ]
399
+ # [ c - 周回数 ]
400
+ #
401
+ def polar
402
+ @phi, @theta, @radius = _to_p3(@x, @y, @z) unless @radius
403
+ @c ||= @phi
404
+ @phi -= (@phi - @c + 0.5).floor
405
+ return [@phi, @theta, @radius, @c]
406
+ end
407
+
408
+ # 経度 / CIRCLE
409
+ #
410
+ # @return [Numeric]
411
+ #
412
+ def phi ; @phi || polar[0] ; end
413
+
414
+ # 緯度 / CIRCLE
415
+ #
416
+ # @return [Numeric]
417
+ #
418
+ def theta ; @theta || polar[1] ; end
419
+
420
+ # 距離
421
+ #
422
+ # @return [Numeric]
423
+ #
424
+ def radius ; @radius || polar[2] ; end
425
+
426
+ # 周回数
427
+ #
428
+ # @return [Numeric]
429
+ #
430
+ def c ; @c || polar[3] ; end
431
+
432
+ # 要素参照
433
+ #
434
+ # @param [String, Symbol] z 要素名('x', 'y', 'z', 'phi', 'theta', 'r', 'c', :x, :y, :z, :phi, :theta, :r, :c)
435
+ #
436
+ # @return [Numeric] 要素の値
437
+ #
438
+ def [](z)
439
+ send(z.to_sym)
440
+ end
441
+
442
+ # 加法
443
+ #
444
+ # @param [When::Ephemeris::Coords] other
445
+ #
446
+ # @return [When::Ephemeris::Coords]
447
+ #
448
+ def +(other)
449
+ raise TypeError, 'operand should be When::Ephemeris::Coords' unless other.kind_of?(Coords)
450
+ self.class.rectangular(x+other.x, y+other.y, z+other.z, c+other.c)
451
+ end
452
+
453
+ # 減法
454
+ #
455
+ # @param [When::Ephemeris::Coords] other
456
+ #
457
+ # @return [When::Ephemeris::Coords]
458
+ #
459
+ def -(other)
460
+ raise TypeError, 'operand should be When::Ephemeris::Coords' unless other.kind_of?(Coords)
461
+ self.class.rectangular(x-other.x, y-other.y, z-other.z, c-other.c)
462
+ end
463
+
464
+ # 点対称の反転
465
+ #
466
+ # @return [When::Ephemeris::Coords]
467
+ #
468
+ def -@
469
+ self.class.polar(phi+0.5, -theta, radius, c)
470
+ end
471
+
472
+ # X 軸を軸とする回転
473
+ #
474
+ # @param [Numeric] t 回転角 / CIRCLE
475
+ #
476
+ # @return [When::Ephemeris::Coords]
477
+ #
478
+ def rotate_x(t)
479
+ cos = cosc(t)
480
+ sin = sinc(t)
481
+ self.class.rectangular(x, y*cos-z*sin, y*sin+z*cos, c)
482
+ end
483
+
484
+ # Y 軸を軸とする回転
485
+ #
486
+ # @param [Numeric] t 回転角 / CIRCLE
487
+ #
488
+ # @return [When::Ephemeris::Coords]
489
+ #
490
+ def rotate_y(t)
491
+ cos = cosc(t)
492
+ sin = sinc(t)
493
+ self.class.rectangular(z*sin+x*cos, y, z*cos-x*sin, c)
494
+ end
495
+
496
+ # Z 軸を軸とする回転
497
+ #
498
+ # @param [Numeric] t 回転角 / CIRCLE
499
+ #
500
+ # @return [When::Ephemeris::Coords]
501
+ #
502
+ def rotate_z(t)
503
+ self.class.polar(phi+t, theta, radius, c+t)
504
+ end
505
+
506
+ #
507
+ # 章動
508
+ #
509
+ # @param [Numeric] c 2000年からの経過世紀
510
+ #
511
+ # @return [When::Ephemeris::Coords]
512
+ #
513
+ def nutation(c)
514
+ rotate_z(delta_p(c)).rotate_x(delta_e(c))
515
+ end
516
+
517
+ #
518
+ # 歳差
519
+ #
520
+ # @param [Numeric] dt 分点からの経過時間 / ベッセル世紀
521
+ # @param [Numeric] t0 分点 / ベッセル世紀
522
+ #
523
+ # @return [When::Ephemeris::Coords]
524
+ #
525
+ def precession(dt, t0)
526
+ return self if (theta.abs>=0.25)
527
+
528
+ b0 = dt / (360 * 3600.0)
529
+ b1 = [+0.302, +0.018]
530
+ b2 = [+0.791, +0.001]
531
+ b3 = [-0.462, -0.042]
532
+
533
+ b1.unshift(2304.250 + 1.396 * t0)
534
+ b2.unshift(polynomial(dt, b1))
535
+ b3.unshift(2004.682 - 0.853 * t0)
536
+
537
+ z0 = b0 * b2[0]
538
+ zt = b0 * polynomial(dt, b2)
539
+ th = b0 * polynomial(dt, b3)
540
+
541
+ a = phi + z0
542
+ b = th / 2
543
+ cA = cosc(a)
544
+ sA = sinc(a)
545
+ tB = tanc(b)
546
+ q = sinc(th)*(tanc(theta) + tB*cA)
547
+
548
+ dRA = atan2(q*sA, 1-q*cA) / CIRCLE
549
+ dDC = atan2(tB*(cA-sA*tanc(dRA/2)), 1) / CIRCLE
550
+
551
+ self.class.polar(phi + dRA + z0 + zt, theta + 2*dDC, radius, @c)
552
+ end
553
+
554
+ # 地心視差 (黄道座標) / 地心位置 -> 測心位置(観測地中心位置)
555
+ #
556
+ # @param [Numeric] t ユリウス日(Terrestrial Time)
557
+ # @param [When::TM::TemporalPosition] t
558
+ # @param [When::Coordinates::Spatial] loc 観測地
559
+ #
560
+ # @return [When::Ephemeris::Coords]
561
+ #
562
+ def parallax(t, loc)
563
+ return self if loc.alt==When::Coordinates::Spatial::Center
564
+ self - loc.coords_diff(t)
565
+ end
566
+
567
+ # 赤道座標 -> 黄道座標
568
+ #
569
+ # @param [Numeric] t ユリウス日(Terrestrial Time)
570
+ # @param [When::TM::TemporalPosition] t
571
+ # @param [When::Coordinates::Spatial] loc 観測地
572
+ #
573
+ # @return [When::Ephemeris::Coords]
574
+ #
575
+ def r_to_y(t, loc=nil)
576
+ t = +t
577
+ loc = loc.datum unless loc.kind_of?(Datum)
578
+ n = loc.axis_of_rotation(t) if loc
579
+ if (n)
580
+ c = rotate_z(+0.25 - n.radius).
581
+ rotate_y(+0.25 - n.theta).
582
+ rotate_z(+n.phi)
583
+ else
584
+ c = self
585
+ end
586
+ return c.rotate_x(-obl(julian_century_from_2000(t)))
587
+ end
588
+
589
+ # 黄道座標 -> 赤道座標
590
+ #
591
+ # @param [Numeric] t ユリウス日(Terrestrial Time)
592
+ # @param [When::TM::TemporalPosition] t
593
+ # @param [When::Coordinates::Spatial] loc 観測地
594
+ #
595
+ # @return [When::Ephemeris::Coords]
596
+ #
597
+ def y_to_r(t, loc=nil)
598
+ t = +t
599
+ c = rotate_x(+obl(julian_century_from_2000(t)))
600
+ loc = loc.datum unless loc.kind_of?(Datum)
601
+ n = loc.axis_of_rotation(t) if loc
602
+ return c unless n
603
+ c.rotate_z(-n.phi).
604
+ rotate_y(-0.25 + n.theta).
605
+ rotate_z(-0.25 + n.radius)
606
+ end
607
+
608
+ # 赤道座標 -> 地平座標
609
+ #
610
+ # @param [Numeric] t ユリウス日(Terrestrial Time)
611
+ # @param [When::TM::TemporalPosition] t
612
+ # @param [When::Coordinates::Spatial] loc 観測地
613
+ #
614
+ # @return [When::Ephemeris::Coords]
615
+ #
616
+ def r_to_h(t, loc)
617
+ rotate_z(-loc.local_sidereal_time(t) / 24).
618
+ rotate_y(loc.lat / (360.0*When::Coordinates::Spatial::DEGREE) - 0.25)
619
+ end
620
+
621
+ # 球面の余弦 spherical law of cosines
622
+ #
623
+ # @param [When::Ephemeris::Coords] other
624
+ #
625
+ # @return [Numeric]
626
+ #
627
+ def spherical_law_of_cosines(other)
628
+ sinc(theta)*sinc(other.theta) + cosc(theta)*cosc(other.theta)*cosc(phi-other.phi)
629
+ end
630
+
631
+ # 太陽から見た地球と惑星の視距離の余弦 - cosine of angle Earth - Sun - Planet
632
+ #
633
+ # @return [Numeric]
634
+ #
635
+ alias :cos_esp :spherical_law_of_cosines
636
+
637
+ # 地球から見た惑星と太陽の視距離の余弦 - cosine of angle Planet - Earth - Sun
638
+ #
639
+ # @param [When::Ephemeris::Coords] planet
640
+ #
641
+ # @return [Numeric]
642
+ #
643
+ def cos_pes(planet)
644
+ spherical_law_of_cosines(self - planet)
645
+ end
646
+
647
+ # 惑星から見た太陽と地球の視距離の余弦(惑星の満ち具合) - cosine of angle Sun - Planet - Earth
648
+ #
649
+ # @param [When::Ephemeris::Coords] planet
650
+ #
651
+ # @return [Numeric]
652
+ #
653
+ def cos_spe(planet)
654
+ planet.spherical_law_of_cosines(planet - self)
655
+ end
656
+
657
+ # 惑星の明るさ - luminosity used cosine of angle Sun - Planet - Earth
658
+ #
659
+ # @param [When::Ephemeris::Coords] planet
660
+ #
661
+ # @return [Numeric]
662
+ #
663
+ def luminosity_spe(planet)
664
+ difference = planet - self
665
+ (planet.spherical_law_of_cosines(difference) + 1) / ( 2 * planet.radius * planet.radius * difference.radius * difference.radius)
666
+ end
667
+
668
+ # オブジェクトの生成
669
+ #
670
+ # @overload initialize(x, y, z, options={ :system=>:rectangular })
671
+ # 引数パターン 1
672
+ # @param [Numeric] x x 座標
673
+ # @param [Numeric] y y 座標
674
+ # @param [Numeric] z z 座標
675
+ # @param [Hash] options { :system=>:rectangular }
676
+ #
677
+ # @overload initialize(phi, theta, radius, c, options={})
678
+ # @param [Numeric] phi 経度 / CIRCLE
679
+ # @param [Numeric] theta 緯度 / CIRCLE
680
+ # @param [Numeric] radius 距離
681
+ # @param [Numeric] c 周回数
682
+ # @param [Hash] options { :system=>:rectangular以外 }
683
+ #
684
+ # @note c - 周回数(デフォルト - phi から生成) z軸の周りを何週して現在の位置にあるかを保持する
685
+ #
686
+ def initialize(*args)
687
+ @options = args[-1].kind_of?(Hash) ? args.pop.dup : {}
688
+ if @options[:system] == :rectangular
689
+ @x, @y, @z, @c = args
690
+ @x ||= 0.0 # X座標
691
+ @y ||= 0.0 # Y座標
692
+ @z ||= 0.0 # Z座標
693
+ else
694
+ @phi, @theta, @radius, @c = args
695
+ @phi ||= 0.0 # 経度
696
+ @theta ||= 0.0 # 緯度
697
+ @radius ||= 1.0 # 距離
698
+ @c ||= @phi # 周期番号
699
+ @phi -= (@phi - @c + 0.5).floor
700
+ end
701
+ end
702
+ end
703
+
704
+ # 天体
705
+ #
706
+ # 天体の特性を定義する
707
+ #
708
+ class CelestialObject < When::BasicTypes::Object
709
+
710
+ include When::Ephemeris
711
+
712
+ # 光行差 / 度
713
+ # @return [Numeric]
714
+ attr_reader :aberration
715
+
716
+ # 光度 / magnitude
717
+ # @return [Numeric]
718
+ attr_reader :luminosity
719
+
720
+ # 天体位置 (黄道座標)
721
+ #
722
+ # @param [Numeric] t ユリウス日(Terrestrial Time)
723
+ # @param [When::TM::TemporalPosition] t
724
+ # @param [When::Coordinates::Spatial, When::Ephemeris::Datum] base 基準地
725
+ #
726
+ # @return [When::Ephemeris::Coords]
727
+ #
728
+ def coords(t, base=nil)
729
+ t = +t
730
+ target_coords = self._coords(t)
731
+ return target_coords unless base
732
+ base_coords = base._coords(t)
733
+ differrence = target_coords - base_coords
734
+ delta_phi = differrence.phi - base_coords.phi
735
+ phi = differrence.phi
736
+ theta = differrence.theta
737
+ if @aberration && @aberration != 0
738
+ phi -= @aberration / 360 * cosc(differrence.phi - target_coords.phi) / target_coords.radius
739
+ end
740
+ if base.respond_to?(:aberration)
741
+ phi += base.aberration / 360 / cosc(theta) * cosc(delta_phi) / base_coords.radius
742
+ theta -= base.aberration / 360 * sinc(theta) * sinc(delta_phi) / base_coords.radius
743
+ end
744
+ Coords.polar(phi, theta, differrence.radius, differrence.c)
745
+ end
746
+ end
747
+
748
+ # 天球上の物体
749
+ #
750
+ # 天球上の物体の特性を定義する
751
+ # 天球上にあるため、座標の基準にならない
752
+ #
753
+ class Star < CelestialObject
754
+ # 分点 / YEAR
755
+ # @return [Numeric]
756
+ attr_reader :t0
757
+
758
+ # 赤経 / DEG
759
+ # @return [Numeric]
760
+ attr_reader :phi
761
+
762
+ # 赤緯 / DEG
763
+ # @return [Numeric]
764
+ attr_reader :theta
765
+
766
+ # 視差 / milli arc SECOND
767
+ # @return [Numeric]
768
+ attr_reader :parallax
769
+
770
+ # 固有運動(赤経) / (milli arc SECOND / year)
771
+ # @return [Numeric]
772
+ attr_reader :delta_phi
773
+
774
+ # 固有運動(赤経) / (milli arc SECOND / year)
775
+ # @return [Numeric]
776
+ attr_reader :delta_theta
777
+
778
+ # 視線速度 / (km/s)
779
+ # @return [Numeric]
780
+ attr_reader :delta_radius
781
+
782
+ # 視半径 / CIRCLE
783
+ #
784
+ # @param [Numeric] t ユリウス日(Terrestrial Time)
785
+ # @param [When::TM::TemporalPosition] t
786
+ # @param [When::Coordinates::Spatial, When::Ephemeris::Datum] base 基準地
787
+ #
788
+ # @return [Numeric]
789
+ #
790
+ def apparent_radius(t, base=nil)
791
+ 0
792
+ end
793
+
794
+ # 視光度 / magnitude
795
+ #
796
+ # @param [Numeric] t ユリウス日(Terrestrial Time)
797
+ # @param [When::TM::TemporalPosition] t
798
+ # @param [When::Coordinates::Spatial, When::Ephemeris::Datum] base 基準地
799
+ #
800
+ # @return [Numeric]
801
+ #
802
+ def apparent_luminosity(t, base=nil)
803
+ @luminosity
804
+ end
805
+
806
+ # Bayer 名
807
+ #
808
+ # @return [String]
809
+ #
810
+ def bayer_name
811
+ @bayer
812
+ end
813
+
814
+ # @private
815
+ def _normalize(args=[], options={})
816
+ t0, phi, theta, parallax, delta_phi, delta_theta, delta_radius, luminosity, bayer = args
817
+ @t0 ||= t0 || 2000.0
818
+ @phi ||= phi || 0.0
819
+ @theta ||= theta || 90.0
820
+ @parallax ||= parallax || 0.0
821
+ @delta_phi ||= delta_phi || 0.0
822
+ @delta_theta ||= delta_theta || 0.0
823
+ @delta_radius ||= delta_radius || 0.0
824
+ @distance ||= PSEC / ([@parallax, 0.1].max / 1000.0)
825
+ @luminosity ||= luminosity
826
+ @bayer ||= bayer
827
+ end
828
+
829
+ # 恒星
830
+ class Fixed < Star
831
+
832
+ Coef = 100.0 / (3600*1000)
833
+
834
+ # 天体位置 (黄道座標)
835
+ #
836
+ # @param [Numeric] t ユリウス日(Terrestrial Time)
837
+ # @param [When::TM::TemporalPosition] t
838
+ #
839
+ # @return [When::Ephemeris::Coords]
840
+ #
841
+ def _coords(t)
842
+ t = +t
843
+ c2000 = julian_century_from_2000(t)
844
+ c1900 = (@t0-1900.0)/100.0
845
+ dt = (t-(EPOCH1900-0.68648354))/BCENT - c1900
846
+ Coords.polar(
847
+ (@phi + dt * @delta_phi * Coef) / 360,
848
+ (@theta + dt * @delta_theta * Coef) / 360,
849
+ @distance - dt * @delta_radius / (AU/(BCENT*86400.0))).
850
+ precession(dt, c1900).
851
+ rotate_x(-obl(c2000)).
852
+ nutation(c2000)
853
+ end
854
+ end
855
+
856
+ # 春分点
857
+ class Vernal < Star
858
+
859
+ # 天体位置 (黄道座標)
860
+ #
861
+ # @param [Numeric] t ユリウス日(Terrestrial Time)
862
+ # @param [When::TM::TemporalPosition] t
863
+ #
864
+ # @return [When::Ephemeris::Coords]
865
+ #
866
+ def _coords(t)
867
+ Coords.polar(0, 0, FARAWAY)
868
+ end
869
+ end
870
+
871
+ # 北極
872
+ class Pole < Star
873
+
874
+ # 天体位置 (黄道座標)
875
+ #
876
+ # @param [Numeric] t ユリウス日(Terrestrial Time)
877
+ # @param [When::TM::TemporalPosition] t
878
+ #
879
+ # @return [When::Ephemeris::Coords]
880
+ #
881
+ def _coords(t)
882
+ Coords.polar(0, +0.25, FARAWAY).r_to_y(+t)
883
+ end
884
+ end
885
+ end
886
+
887
+ # 座標の基準になる天体
888
+ #
889
+ # 座標の基準になる天体の特性を定義する
890
+ #
891
+ class Datum < CelestialObject
892
+ # 半径/km
893
+ # @return [Numeric]
894
+ attr_reader :surface_radius
895
+
896
+ # 計算式の精度保証期間の下限 / ユリウス日
897
+ # @return [Numeric]
898
+ attr_reader :first_day
899
+
900
+ # 計算式の精度保証期間の上限 / ユリウス日
901
+ # @return [Numeric]
902
+ attr_reader :last_day
903
+
904
+ # 黄経の係数
905
+ # @return [Array<Numeric>]
906
+ attr_reader :phi
907
+
908
+ # 黄経の補正の係数
909
+ # @return [Array<Numeric>]
910
+ attr_reader :dl
911
+
912
+ # 黄緯の係数
913
+ # @return [Array<Numeric>]
914
+ attr_reader :theta
915
+
916
+ # 動径の係数
917
+ # @return [Array<Numeric>]
918
+ attr_reader :radius
919
+
920
+ # 木星と土星の相互摂動項
921
+ # @return [Array<Numeric>]
922
+ attr_reader :nn
923
+
924
+ # 黄経の係数1 (木星-土星)
925
+ # @return [Array<Numeric>]
926
+ attr_reader :jsn
927
+
928
+ # 黄経の係数2 (木星-土星)
929
+ # @return [Array<Numeric>]
930
+ attr_reader :jsl
931
+
932
+ # 黄緯の係数 (木星-土星)
933
+ # @return [Array<Numeric>]
934
+ attr_reader :jst
935
+
936
+ # 動径の係数 (木星-土星)
937
+ # @return [Array<Numeric>]
938
+ attr_reader :jsr
939
+
940
+ # 惑星の形
941
+ # @return [Array<Numeric>]
942
+ attr_reader :shape
943
+
944
+ # 自転 - 平均太陽の赤経(2000年分点)
945
+ # @return [Array<Numeric>]
946
+ attr_reader :sid
947
+
948
+ # 天体の出没、薄明の閾値
949
+ # @return [Hash<String=>Numeric>]
950
+ attr_reader :zeros
951
+
952
+ # 大気の補正
953
+ # @return [Array<Numeric>]
954
+ attr_reader :air
955
+
956
+ # 自転軸
957
+ # @return [Array<Numeric>]
958
+ attr_reader :axis
959
+
960
+ #
961
+ # 平均運動 / (DEG / YEAR)
962
+ #
963
+ # @return [Numeric]
964
+ #
965
+ def mean_motion
966
+ return @phi[0][2]
967
+ end
968
+
969
+ #
970
+ # 光行差を含んだ平均黄経 / CIRCLE
971
+ #
972
+ # @param [Numeric] t ユリウス日(Terrestrial Time)
973
+ # @param [When::TM::TemporalPosition] t
974
+ #
975
+ # @return [Numeric]
976
+ #
977
+ def mean_longitude(t)
978
+ coord = _coords(t)
979
+ coord.c - @aberration / coord.radius / 360
980
+ end
981
+
982
+ #
983
+ # 光行差を含んだ真黄経 / CIRCLE
984
+ #
985
+ # @param [Numeric] t ユリウス日(Terrestrial Time)
986
+ # @param [When::TM::TemporalPosition] t
987
+ #
988
+ # @return [Numeric]
989
+ #
990
+ def true_longitude(t)
991
+ coord = _coords(t)
992
+ coord.phi - @aberration / coord.radius / 360
993
+ end
994
+
995
+ #
996
+ # 自転軸の歳差補正
997
+ #
998
+ # @param [Numeric] t ユリウス日(Terrestrial Time)
999
+ # @param [When::TM::TemporalPosition] t
1000
+ #
1001
+ # @return [When::Ephemeris::Coords]
1002
+ #
1003
+ def axis_of_rotation(t)
1004
+ return nil unless @axis
1005
+ c1900 = (@axis[0]-1900.0)/100.0
1006
+ dt = (+t-(EPOCH1900-0.68648354))/BCENT - c1900
1007
+ Coords.polar(
1008
+ (@axis[1][0] + dt * @axis[2][0]) / 360,
1009
+ (@axis[1][1] + dt * @axis[2][1]) / 360,
1010
+ (@axis[1][2] + dt * @axis[2][2]) / 360
1011
+ ).precession(dt, c1900)
1012
+ end
1013
+
1014
+ # 均時差 / DAY
1015
+ #
1016
+ # @param [Numeric] t ユリウス日(Terrestrial Time)
1017
+ # @param [When::TM::TemporalPosition] t
1018
+ #
1019
+ # @return [Numeric]
1020
+ #
1021
+ def equation_of_time(t)
1022
+ t = +t
1023
+ c = julian_century_from_2000(t)
1024
+ coords = _coords(t)
1025
+ coords = coords.rotate_z(0.5 - (@aberration||0) / coords.radius / 360)
1026
+ coords = coords.y_to_r(t, self)
1027
+ return 0.5 - ((coords.phi - (@sid[0] + c * (@sid[1] + c * @sid[2])) / 24.0) % 1)
1028
+ end
1029
+
1030
+ # 視半径 / CIRCLE
1031
+ #
1032
+ # @param [Numeric] t ユリウス日(Terrestrial Time)
1033
+ # @param [When::TM::TemporalPosition] t
1034
+ # @param [When::Coordinates::Spatial, When::Ephemeris::Datum] base 観測地
1035
+ #
1036
+ # @return [Numeric]
1037
+ #
1038
+ def apparent_radius(t, base=Earth)
1039
+ target_coords = self.coords(t, base)
1040
+ asin(@surface_radius / (target_coords.radius * AU)) / CIRCLE
1041
+ end
1042
+
1043
+ # 視光度 / magnitude
1044
+ #
1045
+ # @param [Numeric] t ユリウス日(Terrestrial Time)
1046
+ # @param [When::TM::TemporalPosition] t
1047
+ # @param [When::Coordinates::Spatial, When::Ephemeris::Datum] base 観測地
1048
+ #
1049
+ # @return [Numeric]
1050
+ #
1051
+ def apparent_luminosity(t, base)
1052
+ return @luminosity - 2.5*log10(base._coords(t).luminosity_spe(self._coords(t)))
1053
+ end
1054
+
1055
+ # 離角 / CIRCLE
1056
+ #
1057
+ # @param [Numeric] t ユリウス日(Terrestrial Time)
1058
+ # @param [When::TM::TemporalPosition] t
1059
+ # @param [When::Ephemeris::Datum] target 基準星
1060
+ # @param [When::Coordinates::Spatial, When::Ephemeris::Datum] base 観測地
1061
+ #
1062
+ # @return [Numeric]
1063
+ #
1064
+ def elongation(t, target=Sun, base=Earth)
1065
+ t = +t
1066
+ self_coords = self.coords(t, base)
1067
+ target_coords = target.coords(t, base)
1068
+ elongation = acos(self_coords.spherical_law_of_cosines(target_coords)) / CIRCLE
1069
+ difference = (self_coords.phi - target_coords.phi + 0.5) % 1 - 0.5
1070
+ return (difference >= 0) ? elongation : -elongation
1071
+ end
1072
+
1073
+ # 食分
1074
+ #
1075
+ # @param [Numeric] t ユリウス日(Terrestrial Time)
1076
+ # @param [When::TM::TemporalPosition] t
1077
+ # @param [When::Ephemeris::Datum] target 基準星
1078
+ # @param [When::Coordinates::Spatial, When::Ephemeris::Datum] base 観測地
1079
+ #
1080
+ # @return [Numeric]
1081
+ #
1082
+ def eclipse(t, target, base=Earth)
1083
+ t = +t
1084
+ distance = self.coords(t, base).spherical_law_of_cosines(target.coords(t, base)) / CIRCLE
1085
+ self_radius = self.apparent_radius(t, base)
1086
+ target_radius = target.apparent_radius(t, base)
1087
+ return (self_radius + target_radius - distance) / (2.0 * target_radius)
1088
+ end
1089
+
1090
+ private
1091
+
1092
+ def _normalize(args=[], options={})
1093
+ surface_radius, aberration, luminosity, first_day, last_day = args
1094
+ @surface_radius ||= surface_radius || AU
1095
+ @aberration ||= aberration || 0.00
1096
+ @luminosity ||= luminosity || -15.00
1097
+ @first_day ||= first_day || 990558
1098
+ @last_day ||= last_day || 3912515
1099
+ end
1100
+ end
1101
+
1102
+ #
1103
+ # 暦法オブジェクトに天体暦機能を提供する
1104
+ #
1105
+ class Formula < When::BasicTypes::Object
1106
+
1107
+ include When::Parts::MethodCash
1108
+ include When::Ephemeris
1109
+
1110
+ #
1111
+ # 天体暦機能を When::TM::Calendar クラスに提供する
1112
+ #
1113
+ module Methods
1114
+
1115
+ # 月の位相が指定の周期番号パターンになる最も近い過去の日時
1116
+ #
1117
+ # @param [Numeric] date ユリウス日(Terrestrial Time)
1118
+ # @param [When::TM::TemporalPosition] date
1119
+ # @param [Numeric] n 相対周期番号(n=0 なら date または date の直前が基準)
1120
+ # @param [Numeric] d 単位周期数
1121
+ #
1122
+ # @return [Numeric, When::TM::TemporalPosition] 周期番号が d で割って n になる日時
1123
+ #
1124
+ def nearest_past_from_lunar_phase(date, n=0, d=1)
1125
+ @formula ||= When.Resource(['_ep:Formula?formula=12S', '_ep:Formula?formula=1L'])
1126
+ @formula[-1].nearest_past(date, n, d)
1127
+ end
1128
+
1129
+ # 二十四節気が指定の周期番号パターンになる最も近い過去の日時
1130
+ #
1131
+ # @param [Numeric] date ユリウス日(Terrestrial Time)
1132
+ # @param [When::TM::TemporalPosition] date
1133
+ # @param [Numeric] n 相対周期番号(n=0 なら date または date の直前が基準)
1134
+ # @param [Numeric] d 単位周期数
1135
+ #
1136
+ # @return [Numeric, When::TM::TemporalPosition] 周期番号が d で割って n になる日時
1137
+ #
1138
+ def nearest_past_from_solar_term(date, n=0, d=1)
1139
+ @formula ||= When.Resource(['_ep:Formula?formula=12S', '_ep:Formula?formula=1L'])
1140
+ @formula[0].nearest_past(date, n, d)
1141
+ end
1142
+
1143
+ private
1144
+
1145
+ #
1146
+ # メソッドのレシーバーとなる Formulaオブジェクトを取得する
1147
+ #
1148
+ def forwarded_formula(name, date)
1149
+ return nil unless When::Ephemeris::Formula.method_defined?(name)
1150
+ return @formula[0] if @formula && @formula[0].location
1151
+ return When.Resource('_ep:Formula?location=' + date.location.iri.gsub('&', '%26')) if date.respond_to?(:location)
1152
+ nil
1153
+ end
1154
+ end
1155
+
1156
+ # 計算対象 - 公式の指定
1157
+ # @return [String, Hash]
1158
+ attr_reader :formula
1159
+
1160
+ # 観測地
1161
+ # @return [When::Coordinates::Spatial]
1162
+ attr_reader :location
1163
+
1164
+ # 観測地の基準経度 / 度
1165
+ # @return [Numeric]
1166
+ attr_reader :long
1167
+
1168
+ # 観測地の基準緯度 / 度
1169
+ # @return [Numeric]
1170
+ attr_reader :lat
1171
+
1172
+ # 時刻系('universal' or 'dynamical')
1173
+ # @return [String]
1174
+ attr_reader :time_standard
1175
+
1176
+ # 時刻系が dynamical か
1177
+ # @return [Boolean]
1178
+ attr_reader :is_dynamical
1179
+
1180
+ # 天体オブジェクトを保持するハッシュ
1181
+ # @return [Hash<Symbol=>When::Ephemeris::Datum>]
1182
+ attr_reader :graha
1183
+
1184
+ # Seed
1185
+ # @private
1186
+ CYCLE_0M = 0
1187
+ # @private
1188
+ CYCLE_1M = 1000000
1189
+
1190
+ # Year Event
1191
+ Sgn = [[-1,+1],[-1,-1],[+1,-1],[+1,+1]]
1192
+ Bs = [[11.0, 7.0, 11.0, 7.0],
1193
+ [11.0, 7.0, 11.0, 7.0],
1194
+ [11.0, 7.0, 11.0, 7.0],
1195
+ [14.0, 8.5, 14.0, 8.5],
1196
+ [16.0, 10.0, 16.0, 10.0],
1197
+ [17.0, 14.0, 17.0, 14.0],
1198
+ [17.0, 17.0, 17.0, 17.0]]
1199
+
1200
+ # 日時 -> 周期番号
1201
+ #
1202
+ # @param [Numeric] t ユリウス日(Terrestrial Time)
1203
+ # @param [When::TM::TemporalPosition] t
1204
+ #
1205
+ # @return [Numeric] 周期番号
1206
+ #
1207
+ def time_to_cn(t)
1208
+ @proc.call(t)
1209
+ end
1210
+
1211
+ # 周期番号 -> 日時
1212
+ #
1213
+ # @param [Numeric] cn 周期番号
1214
+ #
1215
+ # @return [Numeric] ユリウス日
1216
+ #
1217
+ def cn_to_time_(cn, time0=nil)
1218
+ time0 ||= (cn - @cycle_number_0m) / @cycle_number_1m
1219
+ root(time0, cn) {|t| time_to_cn(t)}
1220
+ end
1221
+
1222
+ # 指定の周期番号パターンになる最も近い過去の日時
1223
+ #
1224
+ # @param [Numeric] date ユリウス日(Terrestrial Time)
1225
+ # @param [When::TM::TemporalPosition] date
1226
+ # @param [Numeric] n 相対周期番号(n=0 なら date または date の直前が基準)
1227
+ # @param [Numeric] d 単位周期数
1228
+ #
1229
+ # @return [Numeric, When::TM::TemporalPosition] 周期番号が d で割って n になる日時
1230
+ #
1231
+ def nearest_past(date, n=0, d=1)
1232
+ i, f = n.divmod(d)
1233
+ t0 = @is_dynamical ? +date : date.to_f
1234
+ cn = time_to_cn(date).divmod(d)[0] * d + f
1235
+ cn -= d while (t1 = cn_to_time(cn)) > t0
1236
+ _to_seed_type((i == 0) ? t1 : cn_to_time(cn+i*d), date)
1237
+ end
1238
+
1239
+ # 天体の位置情報
1240
+ #
1241
+ # @param [Numeric] t ユリウス日(Terrestrial Time)
1242
+ # @param [When::TM::TemporalPosition] t
1243
+ # @param [Integer] system 座標系
1244
+ #
1245
+ # [ 0 - When::Coordinates::Spatial::ECLIPTIC (黄道座標) ]
1246
+ # [ 1 - When::Coordinates::Spatial::EQUATORIAL (赤道座標) ]
1247
+ # [ 2 - When::Coordinates::Spatial::HORIZONTAL (地平座標) ]
1248
+ #
1249
+ # @param [When::Ephemeris::CelestialObject] target 対象星
1250
+ #
1251
+ # @return [When::Ephemeris::Coords]
1252
+ #
1253
+ def _coords(t, system, target)
1254
+ pos = target.coords(t, @location)
1255
+ pos = pos.y_to_r(t, @location) if system >= 1
1256
+ pos = pos.r_to_h(t, @location) if system >= 2
1257
+ return pos
1258
+ end
1259
+
1260
+ # 日没時に月が見えるか否か
1261
+ #
1262
+ # @param [Numeric] t ユリウス日(Terrestrial Time)
1263
+ # @param [When::TM::TemporalPosition] t
1264
+ #
1265
+ # @return [Numeric]
1266
+ # [ 正 - 見える ]
1267
+ # [ 負 - 見えない ]
1268
+ #
1269
+ # @note 満月に近い場合は考慮されていません。主に新月の初見の確認に用います。
1270
+ #
1271
+ def moon_visibility(t)
1272
+ sun = When.Resource('_ep:Sun')
1273
+ moon = When.Resource('_ep:Moon')
1274
+
1275
+ # 日没時刻
1276
+ t = day_event(+t, +1, sun, 'Z')
1277
+
1278
+ # 月の地平線からの高度
1279
+ h = _coords(t, When::Coordinates::Spatial::HORIZONTAL, moon).theta * 360.0
1280
+
1281
+ # 月と太陽の離角
1282
+ p = moon.elongation(t, sun, @location) * 360.0
1283
+
1284
+ # 指標の計算
1285
+ n = 4.0 - 0.1*p
1286
+ f = p < 40.0 ? 4.0 + n*(n+1)/2 : 4.0
1287
+ return (h / f - 1.0)
1288
+ end
1289
+
1290
+ # 天体の出没最大高度日時
1291
+ #
1292
+ # @param [Numeric] t ユリウス日(Terrestrial Time)
1293
+ # @param [When::TM::TemporalPosition] t
1294
+ # @param [Integer] event
1295
+ # [ -1 - 出 ]
1296
+ # [ 0 - 最大高度 ]
1297
+ # [ +1 - 没 ]
1298
+ # @param [When::Ephemeris::CelestialObject] target 対象星(デフォルトは太陽)
1299
+ # @param [Numeric] height 閾値高度/度
1300
+ # @param [String] height
1301
+ # [ '0' - 太陽の上端が地平線(大気差考慮) - 太陽のデフォルト ]
1302
+ # [ 'A' - 天体の中心が地平線(大気差考慮) - 太陽以外のデフォルト ]
1303
+ # [ 'T' - 夜明け/日暮れ ]
1304
+ #
1305
+ # @return [Numeric, When::TM::TemporalPosotion] 計算結果
1306
+ # [ t が ユリウス日(Terrestrial Time) => ユリウス日(Terrestrial Time) ]
1307
+ # [ t が その他 => When::TM::DateAndTime ]
1308
+ #
1309
+ def day_event(t, event, target=When.Resource('_ep:Sun'), height=nil)
1310
+ # 時刻の初期値
1311
+ dl = @location.long / (360.0 * When::Coordinates::Spatial::DEGREE)
1312
+ t0 = (+t + 0.5 + dl).floor - dl
1313
+ dt = _coords(t0, When::Coordinates::Spatial::EQUATORIAL, target).phi -
1314
+ @location.local_sidereal_time(t0) / 24.0 + 0.25 * event
1315
+ t0 += dt - (dt+0.5).floor
1316
+
1317
+ # 天体の地平座標での高度
1318
+ if event == 0
1319
+ height = nil # 極値検索のため
1320
+ else
1321
+ height ||= target.instance_of?(When::Ephemeris::Sun) ? '0' : 'A'
1322
+ if height.kind_of?(String)
1323
+ height = @location.datum.zeros[height.upcase]
1324
+ raise ArgumentError, 'invalid height string' unless height
1325
+ end
1326
+ height = height / 360.0 - (0.25 - @location.horizon) +
1327
+ [@location.alt / (1000.0 * @location.datum.air[0]), 1].min * @location.datum.zeros['A'] / 360.0
1328
+ end
1329
+
1330
+ # イベントの時刻
1331
+ _to_seed_type(root(t0, height) {|t1| _coords(t1, When::Coordinates::Spatial::HORIZONTAL, target).theta }, t)
1332
+ end
1333
+
1334
+ # 日の出の日時
1335
+ #
1336
+ # @param [Numeric] t ユリウス日(Terrestrial Time)
1337
+ # @param [When::TM::TemporalPosition] t
1338
+ # @param [Numeric] height 閾値高度/度
1339
+ # @param [String] height
1340
+ # [ '0' - 太陽の上端が地平線(大気差考慮) - 太陽のデフォルト ]
1341
+ # [ 'T' - 夜明け ]
1342
+ #
1343
+ # @return [Numeric, When::TM::TemporalPosotion] 日の出の日時(ユリウス日(Terrestrial Time)またはWhen::TM::DateAndTime
1344
+ #
1345
+ def sun_rise(t, height='0')
1346
+ day_event(t, -1, When.Resource('_ep:Sun'), height)
1347
+ end
1348
+
1349
+ # 日の入りの日時
1350
+ #
1351
+ # @param [Numeric] t ユリウス日(Terrestrial Time)
1352
+ # @param [When::TM::TemporalPosition] t
1353
+ # @param [Numeric] height 閾値高度/度
1354
+ # @param [String] height
1355
+ # [ '0' - 太陽の上端が地平線(大気差考慮) - 太陽のデフォルト ]
1356
+ # [ 'T' - 日暮れ ]
1357
+ #
1358
+ # @return [Numeric, When::TM::TemporalPosotion] 日の入りの日時(ユリウス日(Terrestrial Time)またはWhen::TM::DateAndTime
1359
+ #
1360
+ def sun_set(t, height='0')
1361
+ day_event(t, +1, When.Resource('_ep:Sun'), height)
1362
+ end
1363
+
1364
+ # 太陽の最大高度の日時
1365
+ #
1366
+ # @param [Numeric] t ユリウス日(Terrestrial Time)
1367
+ # @param [When::TM::TemporalPosition] t
1368
+ #
1369
+ # @return [Numeric, When::TM::TemporalPosotion] 太陽の最大高度の日時(ユリウス日(Terrestrial Time)またはWhen::TM::DateAndTime
1370
+ #
1371
+ def sun_noon(t)
1372
+ day_event(t, 0, When.Resource('_ep:Sun'))
1373
+ end
1374
+
1375
+ # 月の出の日時
1376
+ #
1377
+ # @param [Numeric] t ユリウス日(Terrestrial Time)
1378
+ # @param [When::TM::TemporalPosition] t
1379
+ # @param [Numeric] height 閾値高度/度
1380
+ # @param [String] height
1381
+ # [ 'A' - 月の中心が地平線 ]
1382
+ #
1383
+ # @return [Numeric, When::TM::TemporalPosotion] 月の出の日時(ユリウス日(Terrestrial Time)またはWhen::TM::DateAndTime
1384
+ # 該当時刻がなければ nil
1385
+ #
1386
+ def moon_rise(t, height='A')
1387
+ _day_event(t, -1, When.Resource('_ep:Moon'), height)
1388
+ end
1389
+
1390
+ # 月の入りの日時
1391
+ #
1392
+ # @param [Numeric] t ユリウス日(Terrestrial Time)
1393
+ # @param [When::TM::TemporalPosition] t
1394
+ # @param [Numeric] height 閾値高度/度
1395
+ # @param [String] height
1396
+ # [ 'A' - 月の中心が地平線 ]
1397
+ #
1398
+ # @return [Numeric, When::TM::TemporalPosotion] 月の入りの日時(ユリウス日(Terrestrial Time)またはWhen::TM::DateAndTime
1399
+ # 該当時刻がなければ nil
1400
+ #
1401
+ def moon_set(t, height='A')
1402
+ _day_event(t, +1, When.Resource('_ep:Moon'), height)
1403
+ end
1404
+
1405
+ # 月の最大高度の日時
1406
+ #
1407
+ # @param [Numeric] t ユリウス日(Terrestrial Time)
1408
+ # @param [When::TM::TemporalPosition] t
1409
+ #
1410
+ # @return [Numeric, When::TM::TemporalPosotion] 月の最大高度の日時(ユリウス日(Terrestrial Time)またはWhen::TM::DateAndTime
1411
+ # 該当時刻がなければ nil
1412
+ #
1413
+ def moon_noon(t)
1414
+ _day_event(t, 0, When.Resource('_ep:Moon'))
1415
+ end
1416
+
1417
+ # 恒星の出没と太陽の位置関係に関するイベントの日時
1418
+ #
1419
+ # @param [Numeric] t ユリウス日(Terrestrial Time)
1420
+ # @param [When::TM::TemporalPosition] t
1421
+ # @param [Integer] event
1422
+ # [ 0 - first visible rising (=ヘリアカル・ライジング) ]
1423
+ # [ 1 - last visible rising ]
1424
+ # [ 2 - last visible setting ]
1425
+ # [ 3 - first visible setting ]
1426
+ # @param [When::Ephemeris::CelestialObject] target 対象の恒星
1427
+ # @param [Numeric] hs 恒星の高度/度(地平線上が正)
1428
+ # @param [Numeric] bs 太陽の伏角/度(地平線上が負, よって通常は正です, デフォルトは Bs表引き)
1429
+ #
1430
+ # @return [Numeric, When::TM::TemporalPosotion] イベントの日時(ユリウス日(Terrestrial Time)またはWhen::TM::DateAndTime
1431
+ #
1432
+ def year_event(t, event, target, hs= @location.datum.zeros['A'], bs=nil)
1433
+ # difference of ecliptic longitude between zenith and target star
1434
+ # when the event happens
1435
+ pos = _coords(+t, When::Coordinates::Spatial::EQUATORIAL, target)
1436
+ long = @location.long / When::Coordinates::Spatial::DEGREE
1437
+ lat = @location.lat / When::Coordinates::Spatial::DEGREE
1438
+ dp = (sind(hs) - sind(lat) * sinc(pos.theta)) /
1439
+ (cosd(lat) * cosc(pos.theta))
1440
+
1441
+ return nil if dp.abs >= 1
1442
+ dp = acos(dp) / CIRCLE
1443
+
1444
+ # The Sun's height when the event happens
1445
+ unless bs
1446
+ mag = target.luminosity
1447
+ bs = Bs[mag<-0.5 ? 0 : (mag<4.5 ? (mag+0.5).floor+1 : 6)][event]
1448
+ end
1449
+
1450
+ # イベントの時刻
1451
+ zenith = Coords.polar(pos.phi+Sgn[event][0]*dp, lat/360.0).r_to_y(+t, @location)
1452
+ s = sind(bs)/cosc(zenith.theta)
1453
+ arc = asin(s) / CIRCLE + 0.25
1454
+ lam = _true_sun(+t).floor+(zenith.phi+Sgn[event][1]*arc).divmod(1)[1]
1455
+ tt = nil
1456
+ loop do
1457
+ tt = root(+t, lam) {|t1| _true_sun(t1)}
1458
+ break if tt >= +t
1459
+ lam += 1
1460
+ end
1461
+ _to_seed_type(day_event((tt+0.5+long/360.0).floor, Sgn[event][0], When.Resource('_ep:Sun'), bs), t)
1462
+ end
1463
+
1464
+ # ユリウス日(Numeric)を seed と同じ型に変換して返します。
1465
+ #
1466
+ # @param [Numeric] d ユリウス日(Terrestrial Time)
1467
+ # @param [Numeric] seed
1468
+ # @param [When::TM::TemporalPosition] seed
1469
+ #
1470
+ # @return [Numeric, When::TM::TemporalPosotion]
1471
+ #
1472
+ def _to_seed_type(d, seed)
1473
+ return d if seed.kind_of?(Numeric)
1474
+ options = seed._attr
1475
+ options[:precision] = nil
1476
+ options[:clock] ||= When::TM::Clock.local_time || When.utc
1477
+ t = When::TM::JulianDate._d_to_t(d)
1478
+ options[:frame].jul_trans(@is_dynamical ? When::TM::JulianDate.dynamical_time(t) :
1479
+ When::TM::JulianDate.universal_time(t), options)
1480
+ end
1481
+
1482
+ private
1483
+
1484
+ # オブジェクトの正規化
1485
+ #
1486
+ # @formula = 計算対象/公式の指定
1487
+ # @location = 観測地
1488
+ # @time_standard = 時刻系('universal' or 'dynamical')
1489
+ # @is_dynamical = true: dynamical, false: universal
1490
+ # @proc = 計算手続き
1491
+ # @cycle_number_0m = t = CYCLE_0M日 での計算対象周期番号
1492
+ # @cycle_number_1m = t = CYCLE_1M日 までの計算対象周期番号の比例定数
1493
+ # @lunation_0m = t = CYCLE_0M日 での朔望月番号
1494
+ # @lunation_1m = t = CYCLE_1M日 までの朔望月番号の比例定数
1495
+ # @sun_0m = t = CYCLE_0M日 での太陽年番号
1496
+ # @sun_1m = t = CYCLE_1M日 までの太陽年番号の比例定数
1497
+ def _normalize(args=[], options={})
1498
+ @location = When.Resource(@location.gsub('%26', '&'), '_l:') if @location.kind_of?(String)
1499
+ @long, @lat = [@location.long / When::Coordinates::Spatial::DEGREE,
1500
+ @location.lat / When::Coordinates::Spatial::DEGREE] if @location
1501
+ @formula ||= '1L'
1502
+ @time_standard ||= 'dynamical'
1503
+ @is_dynamical = (@time_standard[0..0].downcase == 'd')
1504
+
1505
+ _normalize_grahas
1506
+
1507
+ @proc ||=
1508
+ case @formula
1509
+ when Hash
1510
+ @formula['Rem'] = (-@formula['Epoch']) % @formula['Period']
1511
+ @is_dynamical ? proc {|t| (+t + @formula['Rem']) / @formula['Period'] } :
1512
+ proc {|t| (t.to_f + @formula['Rem']) / @formula['Period'] }
1513
+ when /^(\d+)L->(\d+)S$/
1514
+ m, s = $1.to_i, $2.to_i
1515
+ @lunation_0m = _true_lunation_(CYCLE_0M)
1516
+ @lunation_1m = (_true_lunation_(CYCLE_1M) - @lunation_0m) / CYCLE_1M
1517
+ @is_dynamical ? proc {|t| s * p_lunation_to_sun(+t / m) } :
1518
+ proc {|t| s * p_lunation_to_sun(t.to_f / m) }
1519
+ when /^(\d+)S->(\d+)L$/
1520
+ s, m = $1.to_i, $2.to_i
1521
+ @sun_0m = _true_sun_(CYCLE_0M)
1522
+ @sun_1m = (_true_sun_(CYCLE_1M) - @sun_0m) / CYCLE_1M
1523
+ @is_dynamical ? proc {|t| m * p_sun_to_lunation(+t / s) } :
1524
+ proc {|t| m * p_sun_to_lunation(t.to_f / s) }
1525
+ when /^(\d+)M\+(\d+)S$/
1526
+ s, m = $2.to_i, $1.to_i
1527
+ @is_dynamical ? proc{|t| s * p_true_sun(+t) + m * p_true_moon(+t) } :
1528
+ proc{|t| s * p_true_sun(t.to_f) + m * p_true_moon(t.to_f)}
1529
+ when /^(\d+)m\+(\d+)s$/
1530
+ s, m = $2.to_i, $1.to_i
1531
+ @is_dynamical ? proc{|t| s * p_mean_sun(+t) + m * p_mean_moon(+t) } :
1532
+ proc{|t| s * p_mean_sun(t.to_f) + m * p_mean_moon(t.to_f)}
1533
+ when /^(\d+)S$/ ; s=$1.to_i; @is_dynamical ? proc{|t| s * p_true_sun(+t) } : proc{|t| s * p_true_sun(t.to_f) }
1534
+ when /^(\d+)s$/ ; s=$1.to_i; @is_dynamical ? proc{|t| s * p_mean_sun(+t) } : proc{|t| s * p_mean_sun(t.to_f) }
1535
+ when /^(\d+)M$/ ; m=$1.to_i; @is_dynamical ? proc{|t| m * p_true_moon(+t) } : proc{|t| m * p_true_moon(t.to_f) }
1536
+ when /^(\d+)m$/ ; m=$1.to_i; @is_dynamical ? proc{|t| m * p_mean_moon(+t) } : proc{|t| m * p_mean_moon(t.to_f) }
1537
+ when /^(\d+)L$/ ; m=$1.to_i; @is_dynamical ? proc{|t| m * p_true_lunation(+t)} : proc{|t| m * p_true_lunation(t.to_f)}
1538
+ when /^(\d+)l$/ ; m=$1.to_i; @is_dynamical ? proc{|t| m * p_mean_lunation(+t)} : proc{|t| m * p_mean_lunation(t.to_f)}
1539
+ when /^[YRH]\.(\w+)-(\w+)$/i
1540
+ system = 'YRH'.index($1.upcase)
1541
+ method = $2.downcase
1542
+ target = When.Resource($3.capitalize, '_ep:')
1543
+ @is_dynamical ? proc{|t| _coords(+t, system, target)[method]} :
1544
+ proc{|t| _coords(t.to_f, system, target)[method]}
1545
+ else ; raise ArgumentError, "Wrong formula format: #{@formula}"
1546
+ end
1547
+
1548
+ @cycle_number_0m = time_to_cn(CYCLE_0M)
1549
+ @cycle_number_1m = (time_to_cn(CYCLE_1M) - @cycle_number_0m) / CYCLE_1M
1550
+ end
1551
+
1552
+ # 天体の設定
1553
+ def _normalize_grahas
1554
+ @graha = {:Sun => Datum::Sun, :Moon => Datum::Moon}
1555
+ return unless @formula == '2L'
1556
+ base = @location || When.Resource('_ep:Earth')
1557
+ @graha.update({
1558
+ :Mercury => Hindu::ModernGraha.new(When.Resource('_ep:Mercury'), base),
1559
+ :Venus => Hindu::ModernGraha.new(When.Resource('_ep:Venus' ), base),
1560
+ :Mars => Hindu::ModernGraha.new(When.Resource('_ep:Mars' ), base),
1561
+ :Jupiter => Hindu::ModernGraha.new(When.Resource('_ep:Jupiter'), base),
1562
+ :Saturn => Hindu::ModernGraha.new(When.Resource('_ep:Saturn' ), base)
1563
+ })
1564
+ end
1565
+
1566
+ # 日付の一致する event を探す
1567
+ #
1568
+ # 見つからなければ nil
1569
+ #
1570
+ def _day_event(t, event, target=When.Resource('_ep:Sun'), height=nil)
1571
+ today = t.to_i
1572
+ 3.times do
1573
+ r = day_event(t, event, target, height)
1574
+ return r if t.kind_of?(Numeric) || today == r.to_i
1575
+ duration ||= When.Duration('P1D')
1576
+ if today > r.to_i
1577
+ t += duration
1578
+ else
1579
+ t -= duration
1580
+ end
1581
+ end
1582
+ nil
1583
+ end
1584
+
1585
+ #
1586
+ # method cashing
1587
+ #
1588
+ def p_true_sun(t) ; _true_sun(t) end
1589
+ def p_mean_sun(t) ; _mean_sun(t) end
1590
+ def p_true_moon(t) ; _true_moon(t) end
1591
+ def p_mean_moon(t) ; _mean_moon(t) end
1592
+ def p_true_lunation(t) ; _true_lunation(t) end
1593
+ def p_mean_lunation(t) ; _mean_lunation(t) end
1594
+ def p_lunation_to_sun(cn) ; _lunation_to_sun(cn) end
1595
+ def p_sun_to_lunation(cn) ; _sun_to_lunation(cn) end
1596
+
1597
+ # 太陽の視黄経を返します。
1598
+ #
1599
+ # @param [Numeric] t ユリウス日(Terrestrial Time)
1600
+ #
1601
+ # @return [Numeric]
1602
+ #
1603
+ def _true_sun_(t)
1604
+ @graha[:Sun].true_longitude(t)
1605
+ end
1606
+
1607
+ # 月の視黄経を返します。
1608
+ #
1609
+ # @param [Numeric] t ユリウス日(Terrestrial Time)
1610
+ #
1611
+ # @return [Numeric]
1612
+ #
1613
+ def _true_moon_(t)
1614
+ @graha[:Moon].true_longitude(t)
1615
+ end
1616
+
1617
+ # 月の位相(太陽と月の視黄経差)を返します。
1618
+ #
1619
+ # @param [Numeric] t ユリウス日(Terrestrial Time)
1620
+ #
1621
+ # @return [Numeric]
1622
+ #
1623
+ def _true_lunation_(t)
1624
+ _true_moon_(t) - _true_sun_(t)
1625
+ end
1626
+
1627
+ # 太陽の平均黄経を返します。
1628
+ #
1629
+ # @param [Numeric] t ユリウス日(Terrestrial Time)
1630
+ #
1631
+ # @return [Numeric]
1632
+ #
1633
+ def _mean_sun_(t)
1634
+ @graha[:Sun].mean_longitude(t)
1635
+ end
1636
+
1637
+ # 月の平均黄経を返します。
1638
+ #
1639
+ # @param [Numeric] t ユリウス日(Terrestrial Time)
1640
+ #
1641
+ # @return [Numeric]
1642
+ #
1643
+ def _mean_moon_(t)
1644
+ @graha[:Moon].mean_longitude(t)
1645
+ end
1646
+
1647
+ # 月の位相(太陽と月の平均黄経差)を返します。
1648
+ #
1649
+ # @param [Numeric] t ユリウス日(Terrestrial Time)
1650
+ #
1651
+ # @return [Numeric]
1652
+ #
1653
+ def _mean_lunation_(t)
1654
+ _mean_moon_(t) - _mean_sun_(t)
1655
+ end
1656
+
1657
+ # 朔望月番号を太陽年番号に変換して返します。
1658
+ #
1659
+ # @param [Numeric] cn 朔望月番号
1660
+ #
1661
+ # @return [Numeric]
1662
+ #
1663
+ def _lunation_to_sun_(cn)
1664
+ _true_sun(root((cn - @lunation_0m) / @lunation_1m, cn) {|x| _true_lunation(x)})
1665
+ end
1666
+
1667
+ # 太陽年番号を朔望月番号に変換して返します。
1668
+ #
1669
+ # @param [Numeric] cn 太陽年番号
1670
+ #
1671
+ # @return [Numeric]
1672
+ #
1673
+ def _sun_to_lunation_(cn)
1674
+ _true_lunation(root((cn - @sun_0m) / @sun_1m, cn) {|x| _true_sun(x)})
1675
+ end
1676
+ end
1677
+
1678
+ #
1679
+ # Luni-Solar Calendar Formula for Mean Lunation Type
1680
+ #
1681
+ class MeanLunation < Formula
1682
+
1683
+ # 計算の基準経度 / 度
1684
+ # @return [Numeric]
1685
+ attr_reader :long
1686
+
1687
+ # 計算の元期(年)
1688
+ # @return [Numeric]
1689
+ attr_reader :year_epoch
1690
+
1691
+ # 計算の元期(月)
1692
+ # @return [Numeric]
1693
+ attr_reader :month_epoch
1694
+
1695
+ # 計算の元期(日)
1696
+ # @return [Numeric]
1697
+ attr_reader :day_epoch
1698
+
1699
+ # 回帰年
1700
+ # @return [Numeric]
1701
+ attr_reader :year_length
1702
+
1703
+ # 恒星月
1704
+ # @return [Numeric]
1705
+ attr_reader :month_length
1706
+
1707
+ # 朔望月
1708
+ # @return [Numeric]
1709
+ attr_reader :lunation_length
1710
+
1711
+ # 統法
1712
+ # @return [Numeric]
1713
+ attr_reader :denominator
1714
+
1715
+ # 太陽の平均黄経を返します。
1716
+ #
1717
+ # @param [Numeric] t ユリウス日(Terrestrial Time)
1718
+ #
1719
+ # @return [Numeric]
1720
+ #
1721
+ def _mean_sun_(t) (t - @day_epoch) / @year_length + @year_epoch end
1722
+
1723
+ # 月の平均黄経を返します。
1724
+ #
1725
+ # @param [Numeric] t ユリウス日(Terrestrial Time)
1726
+ #
1727
+ # @return [Numeric]
1728
+ #
1729
+ def _mean_moon_(t) (t - @day_epoch) / @month_length + @month_epoch end
1730
+
1731
+ # 日の出の日時
1732
+ #
1733
+ # @param [Numeric] sdn ユリウス日(Terrestrial Time)
1734
+ # @param [Numeric] height 観測地の高度(本クラスでは使用しない)
1735
+ #
1736
+ # @return [Numeric] 日の出の日時のユリウス日
1737
+ #
1738
+ def sun_rise(sdn, height=nil)
1739
+ return sdn.to_i - @long / 360.0 - 0.25
1740
+ end
1741
+
1742
+ # 太陽の視黄経を返します。
1743
+ #
1744
+ # @param [Numeric] t ユリウス日(Terrestrial Time)
1745
+ #
1746
+ # @return [Numeric]
1747
+ #
1748
+ alias :_true_sun_ :_mean_sun_
1749
+
1750
+ # 月の視黄経を返します。
1751
+ #
1752
+ # @param [Numeric] t ユリウス日(Terrestrial Time)
1753
+ #
1754
+ # @return [Numeric]
1755
+ #
1756
+ alias :_true_moon_ :_mean_moon_
1757
+
1758
+ private
1759
+
1760
+ # 周期番号 -> 日時
1761
+ #
1762
+ # @param [Numeric] cn 周期番号
1763
+ # @param [Numeric] time0 日時の初期近似値
1764
+ #
1765
+ # @return [Numeric] ユリウス日
1766
+ #
1767
+ def cn_to_time_(cn, time0=nil)
1768
+ time0 ||= (cn - @cycle_number_0m) / @cycle_number_1m
1769
+ case @formula
1770
+ when /S/ ; (time0 + 1.0/256 - @day_epoch).divmod(@solar_terms)[0] * @solar_terms + @day_epoch
1771
+ when /L/ ; (time0 + 1.0/256 - @day_epoch).divmod(@month_tithi)[0] * @month_tithi + @day_epoch
1772
+ end
1773
+ end
1774
+
1775
+ # オブジェクトの正規化
1776
+ def _normalize(args=[], options={})
1777
+ Rational
1778
+ @time_standard ||= 'universal'
1779
+ @epoch_shift ||= 1721139 # 西暦 0 年 春分
1780
+ @day_shift ||= Rational(-1,2) # 夜半 -1/2, 日出 -1/4
1781
+ @day_shift = @day_shift.to_r
1782
+ @longitude_shift ||= Rational(-1,4) # 冬至 -1/4, 立春 -1/8
1783
+ @longitude_shift = @longitude_shift.to_r
1784
+ @day_epoch = @day_epoch.to_i + @day_shift
1785
+ @year_length = @year_length.to_r
1786
+ @lunation_length = @lunation_length.to_r
1787
+ @month_length = 1 / (1.to_r/@year_length + 1.to_r/@lunation_length)
1788
+ @denominator = [@year_length.denominator, @lunation_length.denominator].max
1789
+ @solar_terms = @year_length / 24
1790
+ @month_tithi = @lunation_length / 30
1791
+ @year_epoch = 0
1792
+ @year_epoch = @longitude_shift -_mean_sun_(@epoch_shift).to_i
1793
+ @month_epoch = 0
1794
+ @month_epoch = @longitude_shift -_mean_moon_(@epoch_shift).to_i
1795
+ super
1796
+ end
1797
+ end
1798
+
1799
+ #
1800
+ # Solar Calendar Formula for Variable Year Length Method
1801
+ #
1802
+ class VariableYearLengthMethod < Formula
1803
+
1804
+ # 日時 -> 周期番号
1805
+ #
1806
+ # @param [Numeric] t ユリウス日(Terrestrial Time)
1807
+ # @param [When::TM::TemporalPosition] t
1808
+ #
1809
+ # @return [Numeric] 周期番号
1810
+ #
1811
+ def time_to_cn(t, cn0=nil)
1812
+ cn0 ||= (t.to_f - @day_epoch) / @year_length + @year_epoch + @longitude_shift
1813
+ root(cn0 * 12, t.to_f) {|cn| cn_to_time(cn) }
1814
+ end
1815
+
1816
+ # 周期番号 -> 日時
1817
+ #
1818
+ # @param [Numeric] cn 周期番号
1819
+ # @param [Numeric] time0 日時の初期近似値
1820
+ #
1821
+ # @return [Numeric] ユリウス日
1822
+ #
1823
+ def cn_to_time_(cn, time0=nil)
1824
+ t, n = (cn / 12.0 - @longitude_shift - @year_epoch).divmod(1)
1825
+ @day_epoch + @year_length * t - @year_delta * t * (t-1) + (@year_length - 2 * @year_delta * t) * n
1826
+ end
1827
+
1828
+ private
1829
+
1830
+ # オブジェクトの正規化
1831
+ def _normalize(args=[], options={})
1832
+ Rational
1833
+ @time_standard ||= 'universal'
1834
+ @day_shift ||= Rational(-1,2) # 夜半 -1/2, 日出 -1/4
1835
+ @day_shift = @day_shift.to_r
1836
+ @longitude_shift ||= Rational(-1,4) # 冬至 -1/4, 立春 -1/8
1837
+ @longitude_shift = @longitude_shift.to_r
1838
+ @day_epoch = @day_epoch.to_f + @day_shift
1839
+ @year_epoch = @year_epoch.to_f
1840
+ @year_length = @year_length.to_f
1841
+ @year_delta = @year_delta.to_f * 1.0E-6
1842
+ super
1843
+ end
1844
+ end
1845
+ end