when_exe 0.3.6 → 0.3.7

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