when_exe 0.4.1 → 0.4.2

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