when_exe 0.3.6 → 0.3.7

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