when_exe 0.2.100 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
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