when_exe 0.4.1 → 0.4.2

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