when_exe 0.3.6 → 0.3.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (117) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +171 -0
  3. data/lib/when_exe.rb +78 -47
  4. data/lib/when_exe/basictypes.rb +752 -747
  5. data/lib/when_exe/calendarnote.rb +805 -801
  6. data/lib/when_exe/calendartypes.rb +1583 -1531
  7. data/lib/when_exe/coordinates.rb +16 -15
  8. data/lib/when_exe/core/duration.rb +114 -110
  9. data/lib/when_exe/core/extension.rb +504 -504
  10. data/lib/when_exe/ephemeris.rb +1917 -1913
  11. data/lib/when_exe/ephemeris/moon.rb +333 -333
  12. data/lib/when_exe/ephemeris/notes.rb +389 -387
  13. data/lib/when_exe/ephemeris/planets.rb +585 -585
  14. data/lib/when_exe/ephemeris/sun.rb +214 -214
  15. data/lib/when_exe/googlecalendar.rb +144 -140
  16. data/lib/when_exe/icalendar.rb +1636 -1636
  17. data/lib/when_exe/inspect.rb +46 -22
  18. data/lib/when_exe/locales/akt.rb +176 -176
  19. data/lib/when_exe/locales/encoding_conversion.rb +134 -126
  20. data/lib/when_exe/locales/iast.rb +90 -90
  21. data/lib/when_exe/locales/locale.rb +750 -746
  22. data/lib/when_exe/locales/transliteration_table.rb +62 -62
  23. data/lib/when_exe/mini_application.rb +307 -305
  24. data/lib/when_exe/parts/enumerator.rb +2 -2
  25. data/lib/when_exe/parts/geometric_complex.rb +397 -397
  26. data/lib/when_exe/parts/method_cash.rb +224 -224
  27. data/lib/when_exe/parts/resource.rb +1069 -1071
  28. data/lib/when_exe/parts/timezone.rb +240 -230
  29. data/lib/when_exe/region/armenian.rb +56 -56
  30. data/lib/when_exe/region/babylonian.rb +405 -0
  31. data/lib/when_exe/region/bahai.rb +146 -146
  32. data/lib/when_exe/region/balinese.rb +622 -622
  33. data/lib/when_exe/region/chinese.rb +95 -25
  34. data/lib/when_exe/region/chinese/calendars.rb +1016 -1016
  35. data/lib/when_exe/region/chinese/epochs.rb +1 -1
  36. data/lib/when_exe/region/chinese/twins.rb +803 -795
  37. data/lib/when_exe/region/christian.rb +824 -824
  38. data/lib/when_exe/region/coptic.rb +106 -87
  39. data/lib/when_exe/region/discordian.rb +225 -225
  40. data/lib/when_exe/region/far_east.rb +188 -188
  41. data/lib/when_exe/region/french.rb +56 -56
  42. data/lib/when_exe/region/geologicalage.rb +639 -639
  43. data/lib/when_exe/region/goddess.rb +58 -58
  44. data/lib/when_exe/region/indian.rb +1254 -1251
  45. data/lib/when_exe/region/iranian.rb +8 -8
  46. data/lib/when_exe/region/islamic.rb +3 -3
  47. data/lib/when_exe/region/japanese.rb +93 -99
  48. data/lib/when_exe/region/japanese/calendars.rb +396 -397
  49. data/lib/when_exe/region/japanese/epochs.rb +26 -26
  50. data/lib/when_exe/region/japanese/nihon_shoki.rb +71 -71
  51. data/lib/when_exe/region/japanese/notes.rb +1383 -1386
  52. data/lib/when_exe/region/japanese/residues.rb +1306 -1306
  53. data/lib/when_exe/region/japanese/twins.rb +225 -225
  54. data/lib/when_exe/region/japanese/weeks.rb +112 -0
  55. data/lib/when_exe/region/javanese.rb +230 -230
  56. data/lib/when_exe/region/jewish.rb +126 -126
  57. data/lib/when_exe/region/korean.rb +378 -378
  58. data/lib/when_exe/region/m17n.rb +114 -113
  59. data/lib/when_exe/region/martian.rb +258 -255
  60. data/lib/when_exe/region/mayan.rb +32 -32
  61. data/lib/when_exe/region/residue.rb +89 -89
  62. data/lib/when_exe/region/roman.rb +36 -24
  63. data/lib/when_exe/region/ryukyu.rb +97 -97
  64. data/lib/when_exe/region/shire.rb +240 -240
  65. data/lib/when_exe/region/soviet.rb +209 -0
  66. data/lib/when_exe/region/symmetry.rb +50 -50
  67. data/lib/when_exe/region/thai.rb +336 -335
  68. data/lib/when_exe/region/tibetan.rb +316 -315
  69. data/lib/when_exe/region/vietnamese.rb +440 -439
  70. data/lib/when_exe/region/weekdate.rb +80 -80
  71. data/lib/when_exe/region/world.rb +175 -175
  72. data/lib/when_exe/region/yerm.rb +14 -14
  73. data/lib/when_exe/region/zoroastrian.rb +203 -203
  74. data/lib/when_exe/timestandard.rb +707 -681
  75. data/lib/when_exe/tmduration.rb +338 -330
  76. data/lib/when_exe/tmobjects.rb +1346 -1325
  77. data/lib/when_exe/tmposition.rb +2115 -2072
  78. data/lib/when_exe/tmreference.rb +1693 -1669
  79. data/lib/when_exe/version.rb +1 -1
  80. data/link_to_online_documents +1 -1
  81. data/test/examples/JapanHolidaysRFC6350.ics +1 -1
  82. data/test/test.rb +67 -61
  83. data/test/test/basictypes.rb +409 -409
  84. data/test/test/calendarnote.rb +86 -69
  85. data/test/test/calendartypes.rb +97 -97
  86. data/test/test/coordinates.rb +396 -396
  87. data/test/test/ephemeris.rb +83 -74
  88. data/test/test/ephemeris/moon.rb +14 -14
  89. data/test/test/ephemeris/planets.rb +14 -14
  90. data/test/test/ephemeris/sun.rb +14 -14
  91. data/test/test/googlecalendar.rb +194 -176
  92. data/test/test/icalendar.rb +867 -858
  93. data/test/test/inspect.rb +117 -117
  94. data/test/test/parts.rb +487 -487
  95. data/test/test/region/balinese.rb +34 -0
  96. data/test/test/region/chinese.rb +218 -206
  97. data/test/test/region/christian.rb +245 -245
  98. data/test/test/region/coptic.rb +27 -27
  99. data/test/test/region/french.rb +33 -33
  100. data/test/test/region/geologicalage.rb +17 -17
  101. data/test/test/region/indian.rb +57 -57
  102. data/test/test/region/iran.rb +54 -54
  103. data/test/test/region/islamic.rb +18 -18
  104. data/test/test/region/japanese.rb +237 -219
  105. data/test/test/region/jewish.rb +61 -61
  106. data/test/test/region/m17n.rb +184 -184
  107. data/test/test/region/mayan.rb +195 -195
  108. data/test/test/region/residue.rb +147 -139
  109. data/test/test/region/thai.rb +116 -116
  110. data/test/test/region/tibetan.rb +30 -30
  111. data/test/test/region/vietnamese.rb +102 -102
  112. data/test/test/region/yerm.rb +146 -146
  113. data/test/test/timestandard.rb +81 -81
  114. data/test/test/tmobjects.rb +328 -328
  115. data/test/test/tmposition.rb +397 -284
  116. data/test/test/tmreference.rb +157 -157
  117. metadata +13 -10
@@ -1,387 +1,389 @@
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
- # Ephemeris を用いる暦注
10
- #
11
- class When::CalendarNote
12
- #
13
- # 太陽と月の位置によるイベント
14
- #
15
- class LuniSolarPositions < self
16
-
17
- # 座標の分子
18
- #
19
- # @return [Numeric]
20
- #
21
- attr_reader :num
22
-
23
- # 座標の分母
24
- #
25
- # @return [Numeric]
26
- #
27
- attr_reader :den
28
-
29
- # 計算アルゴリズム
30
- #
31
- # @return [When::Ephemeris::Formula]
32
- #
33
- attr_reader :formula
34
-
35
- # enumerator の周期
36
- #
37
- # @return [Numeric]
38
- #
39
- attr_reader :delta
40
-
41
- # 没滅計算用の補正
42
- #
43
- # @return [Numeric]
44
- #
45
- attr_reader :margin
46
-
47
- # イベントの日時
48
- #
49
- # @param [When::TM::TemporalPosition] date イベントを探す基準とする日時
50
- # @param [Array<Numeric>] parameter 座標の分子と分母( num, den)
51
- #
52
- # num 座標の分子 (デフォルト @num)
53
- #
54
- # den 座標の分母 (デフォルト @den)
55
- #
56
- # @param [String] parameter 座標の分子と分母("#{ num }/#{ den }" の形式)
57
- # @param [Integer] precision 取得したい時間位置の分解能(デフォルト date の分解能)
58
- #
59
- # @return [When::TM::CalDate] date またはその直後のイベントの日時
60
- #
61
- def event(date, parameter=nil, precision=date.precision)
62
- num, den = parameter.kind_of?(String) ? parameter.split(/\//, 2) : parameter
63
- num = (num || @num).to_f
64
- den = (den || @den).to_f
65
- date = date.floor(precision) if precision < date.precision
66
- options = date._attr
67
- is_date_and_time = options.key?(:clock) || precision > When::DAY
68
- options[:precision] = precision
69
- options[:clock] ||= date.frame.time_basis || When::TM::Clock.local_time
70
- quot, mod = (@formula.time_to_cn(date)*30.0).divmod(den)
71
- cycle = quot * den + num
72
- cycle += den if mod > (num % den)
73
- time = When::TM::JulianDate._d_to_t(@formula.cn_to_time(cycle/30.0))
74
- time = date.time_standard.from_dynamical_time(time) if @formula.is_dynamical
75
- event = date.frame.jul_trans(When::TM::JulianDate.universal_time(time), options)
76
- is_date_and_time ? event : event.to_cal_date
77
- end
78
-
79
- # 日付に対応する座標
80
- #
81
- # @param [When::TM::TemporalPosition] date 日付
82
- # @param [Numeric] delta 周期の補正(土用の時刻の補正に使用,デフォルト 0)
83
- #
84
- # @return [Array<Integer>] Array< Integer, 0 or 1 or 2 >
85
- #
86
- # [Integer] 対応する座標
87
- #
88
- # [0 or 1 or 2] 座標の進み(0 なら 没, 2 なら滅)
89
- #
90
- def position(date, delta=0)
91
- date = date.floor
92
- p0, p1 = [date, date.succ].map {|d| (30.0 * @formula.time_to_cn(d) - @margin + delta).floor}
93
- [p1 % @den, p1 - p0]
94
- end
95
-
96
- #
97
- # イベントの標準的な間隔を返す
98
- #
99
- # @param [String] parameter 座標の分子と分母("#{ num }/#{ den }" の形式)
100
- #
101
- # @return [When::TM::IntervalLength]
102
- #
103
- # @private
104
- def event_delta(parameter=nil)
105
- return @delta unless parameter
106
- num, den = parameter.split(/\//, 2)
107
- When::TM::IntervalLength.new([(den || @den).to_f,1].max*0.9, 'day')
108
- end
109
-
110
- #
111
- # イベント日付(時刻付)
112
- #
113
- # @private
114
- def event_time(date, event_name, event)
115
- etime = term(date - When.Duration('P3D'), event, When::SYSTEM)
116
- if formula.respond_to?(:year_length) && formula.denominator && formula.denominator < 100000
117
- fraction = etime.clk_time.universal_time
118
- fraction += When::TM::Duration::DAY * (etime.to_i - date.to_i)
119
- fraction = (fraction / When::TM::Duration::DAY * formula.denominator * 1000 + 0.5).floor / 1000.0
120
- fraction = fraction.to_i if fraction == fraction.to_i
121
- event_name + "(#{fraction}/#{formula.denominator})"
122
- else
123
- etime.events = [event_name]
124
- etime
125
- end
126
- end
127
- end
128
-
129
- #
130
- # 二十四節気
131
- #
132
- class SolarTerms < LuniSolarPositions
133
-
134
- # 二十四節気のための event の別名
135
- #
136
- # @return [When::TM::CalDate] date またはその直後のイベントの日時
137
- alias :term :event
138
-
139
- private
140
-
141
- # 二十四節気のための event_delta の別名
142
- alias :term_delta :event_delta
143
-
144
- # オブジェクトの正規化
145
- # num - 太陽黄経/度の分子 (デフォルト 0 - 春分)
146
- # den - 太陽黄経/度の分母 (デフォルト 360 - 1年)
147
- # formula - 計算アルゴリズム(デフォルト '_ep:Formula?formula=12S')
148
- # delta - enumerator の周期 (デフォルト (den/360)年)
149
- # margin - 没滅計算用の補正 (デフォルト 1E-8)
150
- def _normalize(args=[], options={})
151
- num, den, formula, delta, margin = args
152
- @num = (num || @num || 0).to_f
153
- @den = (den || @den || 360).to_f
154
- @formula = When.Resource(formula || @formula ||'Formula?formula=12S', '_ep:')
155
- @delta = When.Duration(delta || @delta || When::TM::IntervalLength.new(@den/360, 'year'))
156
- @margin = (margin || @margin || 1E-8).to_f
157
- super
158
- end
159
- end
160
-
161
- #
162
- # 月の位相
163
- #
164
- class LunarPhases < LuniSolarPositions
165
-
166
- # 月の位相のための event の別名
167
- #
168
- # @return [When::TM::CalDate] date またはその直後のイベントの日時
169
- alias :phase :event
170
-
171
- private
172
-
173
- # 月の位相のための event_delta の別名
174
- alias :phase_delta :event_delta
175
-
176
- # オブジェクトの正規化
177
- # num - 月の位相/12度の分子 (デフォルト 0 - 朔)
178
- # den - 月の位相/12度の分母 (デフォルト 30 - 1月)
179
- # formula - 計算アルゴリズム(デフォルト '_ep:Formula?formula=1L')
180
- # delta - enumerator の周期 (デフォルト (den/30)月)
181
- # margin - 没滅計算用の補正 (デフォルト 1E-8)
182
- def _normalize(args=[], options={})
183
- num, den, formula, delta, margin = args
184
- @num = (num || @num || 0).to_f
185
- @den = (den || @den || 30).to_f
186
- @formula = When.Resource(formula || @formula ||'Formula?formula=1L', '_ep:')
187
- @delta = When.Duration(delta || @delta || When::TM::IntervalLength.new(@den/30, 'month'))
188
- @margin = (margin || @margin || 1E-8).to_f
189
- super
190
- end
191
- end
192
-
193
- #
194
- # 天体暦の暦注
195
- #
196
- class Ephemeris < self
197
-
198
- Notes = [When::BasicTypes::M17n, [
199
- "locale:[=en:, ja=ja:, alias=ja:]",
200
- "names:[Ephemeris]",
201
-
202
- # 年の暦注 ----------------------------
203
- [When::BasicTypes::M17n,
204
- "names:[year]"
205
- ],
206
-
207
- # 月の暦注 ----------------------------
208
- [When::BasicTypes::M17n,
209
- "names:[month]",
210
- [When::BasicTypes::M17n,
211
- "names:[Month]"
212
- ]
213
- ],
214
-
215
- # 日の暦注 ----------------------------
216
- [When::BasicTypes::M17n,
217
- "names:[day]",
218
- "[Sunrise, 日の出 ]", # 日の出
219
- "[Sunset, 日の入り ]", # 日の入り
220
- [When::Coordinates::Residue,
221
- "label:[Moon_Age=, 正午月齢=ja:%%<月齢>]",
222
- "divisor:60",
223
- "format:[%s(%4.1f)=]"
224
- ],
225
- "[Moonrise, 月の出 ]", # 月の出
226
- "[Moonset=, 月の入り ]", # 月の入り
227
- [When::BasicTypes::M17n,
228
- "names:[Tide, 潮汐]", # 満潮干潮日時
229
- "[High_Tide=en:Tide, 満潮=ja:%%<潮汐>]",
230
- "[Low_Tide=en:Tide, 干潮=ja:%%<潮汐>]"
231
- ]
232
- ]
233
- ]]
234
-
235
- #
236
- # 日の出
237
- #
238
- # @param [When::TM::TemporalPosition] date
239
- # @param [Hash] options dummy
240
- #
241
- # @return [When::TM::TemporalPosition] 日の出の時刻をイベント時刻とする
242
- #
243
- def sunrise(date, options={})
244
- event = formula(date.location.iri).sunrise(date)
245
- event.events = [@root['Sunrise']]
246
- event
247
- rescue
248
- nil
249
- end
250
-
251
- #
252
- # 日の入り
253
- #
254
- # @param [When::TM::TemporalPosition] date
255
- # @param [Hash] options dummy
256
- #
257
- # @return [When::TM::TemporalPosition] 日の入りの時刻をイベント時刻とする
258
- #
259
- def sunset(date, options={})
260
- event = formula(date.location.iri).sunset(date)
261
- event.events = [@root['Sunset']]
262
- event
263
- rescue
264
- nil
265
- end
266
-
267
- #
268
- # 正午月齢
269
- #
270
- # @param [When::TM::TemporalPosition] date
271
- # @param [Hash] options dummy
272
- #
273
- # @return [Numeric] 正午における朔からの経過日数
274
- #
275
- def moon_age(date, options={})
276
- @phase ||= When.CalendarNote('LunarPhases')
277
- noon = date.floor(When::DAY,When::SYSTEM) + 0.5
278
- @root['Moon_Age'][noon.to_f - @phase.phase(noon, [-30.0,30.0]).to_f]
279
- end
280
-
281
- #
282
- # 月の出
283
- #
284
- # @param [When::TM::TemporalPosition] date
285
- # @param [Hash] options dummy
286
- #
287
- # @return [When::TM::TemporalPosition] 月の出の時刻をイベント時刻とする
288
- #
289
- def moonrise(date, options={})
290
- event = formula(date.location.iri).moonrise(date)
291
- event.events = [@root['Moonrise']]
292
- event
293
- rescue
294
- nil
295
- end
296
-
297
- #
298
- # 月の入り
299
- #
300
- # @param [When::TM::TemporalPosition] date
301
- # @param [Hash] options dummy
302
- #
303
- # @return [When::TM::TemporalPosition] 月の入りの時刻をイベント時刻とする
304
- #
305
- def moonset(date, options={})
306
- event = formula(date.location.iri).moonset(date)
307
- event.events = [@root['Moonset']]
308
- event
309
- rescue
310
- nil
311
- end
312
-
313
- # 干潮・満潮の日時
314
- #
315
- # @param [When::TM::TemporalPosition] date
316
- # @param [Hash] options 以下の通り
317
- # @option options [String] tide 潮汐計算方式 'Horizontal' - 地平高度基準, 'Equatorial' - 子午線通過基準(デフォルト)
318
- #
319
- # @return [Array<Array<Integer, When::TM::TemporalPosotion>>] 干潮・満潮の日時の Array
320
- #
321
- # [Integer] +1:満潮, -1:干潮
322
- #
323
- # [When::TM::TemporalPosotion] 干潮・満潮の日時
324
- #
325
- #
326
- def tide(date, options={})
327
- return nil unless @interval
328
- @target ||= When.Resource('_ep:Moon')
329
- events = @root['Tide']
330
- form = formula(date.location.iri)
331
- type = options[:tide] =~ /^horizon/i ? nil : 0
332
-
333
- now = +date
334
- high_tides = []
335
- 5.times do |i|
336
- high_tide = form.day_event(now + i - 2, type, @target) + @interval
337
- high_tides << high_tide if high_tides.size == 0 || high_tide > high_tides[-1] + 0.5
338
- end
339
- tides = []
340
-
341
- (high_tides.size-1).times do |i|
342
- tides << [0, high_tides[i]]
343
- tides << [1, 0.75*high_tides[i] + 0.25*high_tides[i+1]]
344
- tides << [0, 0.50*high_tides[i] + 0.50*high_tides[i+1]]
345
- tides << [1, 0.25*high_tides[i] + 0.75*high_tides[i+1]]
346
- end
347
- tides << [0, high_tides[-1]]
348
-
349
- today = +date.floor(When::DAY)...+date.ceil(When::DAY)
350
- seed = date._attr
351
- seed[:clock] ||= When::TM::Clock.local_time
352
- tides.select {|x| today.include?(x[1])}.map {|x|
353
- d = form._to_seed_type(x[1], seed)
354
- d.events = [events[x[0]]]
355
- d
356
- }
357
- rescue
358
- nil
359
- end
360
-
361
- private
362
-
363
- # オブジェクトの正規化
364
- # long - 計算に用いる経度 / 度
365
- # lat - 計算に用いる緯度 / 度
366
- # alt - 計算に用いる高度 / m
367
- # interval - 高潮間隔(月の子午線通過から満潮までの時間) / 時間
368
- def _normalize(args=[], options={})
369
- if @location
370
- @location = When.Resource(@location)
371
- @formula = When.Resource(@formula || "Formula?location=(#{@location.iri})", '_ep:')
372
- else
373
- @formula = {}
374
- end
375
- @interval = @interval.sub('@','.').to_f / 24 if @interval
376
- @root = When.CalendarNote('Ephemeris/Notes::day')
377
- @prime ||= [%w(Month), %w(Sunrise Sunset Moon_Age)]
378
- super
379
- end
380
-
381
- # 計算に用いる Ephemeris
382
- def formula(location)
383
- return @formula unless @formula.kind_of?(Hash)
384
- @formula[location] ||= When.Resource("Formula?location=(#{location})", '_ep:')
385
- end
386
- end
387
- end
1
+ # -*- coding: utf-8 -*-
2
+ =begin
3
+ Copyright (C) 2011-2014 Takashi SUGA
4
+
5
+ You may use and/or modify this file according to the license described in the LICENSE.txt file included in this archive.
6
+ =end
7
+
8
+ #
9
+ # Ephemeris を用いる暦注
10
+ #
11
+ class When::CalendarNote
12
+ #
13
+ # 太陽と月の位置によるイベント
14
+ #
15
+ class LuniSolarPositions < self
16
+
17
+ # 座標の分子
18
+ #
19
+ # @return [Numeric]
20
+ #
21
+ attr_reader :num
22
+
23
+ # 座標の分母
24
+ #
25
+ # @return [Numeric]
26
+ #
27
+ attr_reader :den
28
+
29
+ # 計算アルゴリズム
30
+ #
31
+ # @return [When::Ephemeris::Formula]
32
+ #
33
+ attr_reader :formula
34
+
35
+ # enumerator の周期
36
+ #
37
+ # @return [Numeric]
38
+ #
39
+ attr_reader :delta
40
+
41
+ # 没滅計算用の補正
42
+ #
43
+ # @return [Numeric]
44
+ #
45
+ attr_reader :margin
46
+
47
+ # イベントの日時
48
+ #
49
+ # @param [When::TM::TemporalPosition] date イベントを探す基準とする日時
50
+ # @param [Array<Numeric>] parameter 座標の分子と分母( num, den)
51
+ #
52
+ # num 座標の分子 (デフォルト @num)
53
+ #
54
+ # den 座標の分母 (デフォルト @den)
55
+ #
56
+ # @param [String] parameter 座標の分子と分母("#{ num }/#{ den }" の形式)
57
+ # @param [Integer] precision 取得したい時間位置の分解能(デフォルト date の分解能)
58
+ #
59
+ # @return [When::TM::CalDate] date またはその直後のイベントの日時
60
+ #
61
+ def event_eval(date, parameter=@event, precision=date.precision)
62
+ num, den = parameter.kind_of?(String) ? parameter[/\d.*\z/].split(/\//, 2) : parameter
63
+ num = (num || @num).to_f
64
+ den = (den || @den).to_f
65
+ date = date.floor(precision) if precision < date.precision
66
+ options = date._attr
67
+ is_date_and_time = options.key?(:clock) || precision > When::DAY
68
+ options[:precision] = precision
69
+ options[:clock] ||= date.frame.time_basis || When::TM::Clock.local_time
70
+ quot, mod = (@formula.time_to_cn(date)*30.0).divmod(den)
71
+ cycle = quot * den + num
72
+ cycle += den if mod > (num % den)
73
+ time = When::TM::JulianDate._d_to_t(@formula.cn_to_time(cycle/30.0))
74
+ time = date.time_standard.from_dynamical_time(time) if @formula.is_dynamical
75
+ event = date.frame.jul_trans(When::TM::JulianDate.universal_time(time), options)
76
+ is_date_and_time ? event : event.to_cal_date
77
+ end
78
+
79
+ # 日付に対応する座標
80
+ #
81
+ # @param [When::TM::TemporalPosition] date 日付
82
+ # @param [Numeric] delta 周期の補正(土用の時刻の補正に使用,デフォルト 0)
83
+ #
84
+ # @return [Array<Integer>] Array< Integer, 0 or 1 or 2 >
85
+ #
86
+ # [Integer] 対応する座標
87
+ #
88
+ # [0 or 1 or 2] 座標の進み(0 なら 没, 2 なら滅)
89
+ #
90
+ def position(date, delta=0)
91
+ date = date.floor
92
+ p0, p1 = [date, date.succ].map {|d| (30.0 * @formula.time_to_cn(d) - @margin + delta).floor}
93
+ [p1 % @den, p1 - p0]
94
+ end
95
+
96
+ #
97
+ # イベントの標準的な間隔を返す
98
+ #
99
+ # @param [String] parameter 座標の分子と分母("#{ num }/#{ den }" の形式)
100
+ #
101
+ # @return [When::TM::IntervalLength]
102
+ #
103
+ # @private
104
+ def event_delta(parameter=nil)
105
+ return @delta unless parameter
106
+ num, den = parameter.kind_of?(String) ? parameter.split(/\//, 2) : parameter
107
+ When::TM::IntervalLength.new([(den || @den).to_f,1].max*0.9, 'day')
108
+ end
109
+
110
+ #
111
+ # イベント日付(時刻付)
112
+ #
113
+ # @private
114
+ def event_time(date, event_name, event)
115
+ etime = term(date - When.Duration('P3D'), event, When::SYSTEM)
116
+ if formula.respond_to?(:year_length) && formula.denominator && formula.denominator < 100000
117
+ fraction = etime.clk_time.universal_time
118
+ fraction += When::TM::Duration::DAY * (etime.to_i - date.to_i)
119
+ fraction = (fraction / When::TM::Duration::DAY * formula.denominator * 1000 + 0.5).floor / 1000.0
120
+ fraction = fraction.to_i if fraction == fraction.to_i
121
+ event_name + "(#{fraction}/#{formula.denominator})"
122
+ else
123
+ etime.events = [event_name]
124
+ etime
125
+ end
126
+ end
127
+ end
128
+
129
+ #
130
+ # 二十四節気
131
+ #
132
+ class SolarTerms < LuniSolarPositions
133
+
134
+ # 二十四節気のための event の別名
135
+ #
136
+ # @return [When::TM::CalDate] date またはその直後のイベントの日時
137
+ alias :term :event_eval
138
+
139
+ private
140
+
141
+ # 二十四節気のための event_delta の別名
142
+ alias :term_delta :event_delta
143
+
144
+ # オブジェクトの正規化
145
+ # num - 太陽黄経/度の分子 (デフォルト 0 - 春分)
146
+ # den - 太陽黄経/度の分母 (デフォルト 360 - 1年)
147
+ # formula - 計算アルゴリズム(デフォルト '_ep:Formula?formula=12S')
148
+ # delta - enumerator の周期 (デフォルト (den/360)年)
149
+ # margin - 没滅計算用の補正 (デフォルト 1E-8)
150
+ def _normalize(args=[], options={})
151
+ num, den, formula, delta, margin = args
152
+ @event ||= 'term'
153
+ @num = (num || @num || 0).to_f
154
+ @den = (den || @den || 360).to_f
155
+ @formula = When.Resource(formula || @formula ||'Formula?formula=12S', '_ep:')
156
+ @delta = When.Duration(delta || @delta || When::TM::IntervalLength.new(@den/360, 'year'))
157
+ @margin = (margin || @margin || 1E-8).to_f
158
+ super
159
+ end
160
+ end
161
+
162
+ #
163
+ # 月の位相
164
+ #
165
+ class LunarPhases < LuniSolarPositions
166
+
167
+ # 月の位相のための event の別名
168
+ #
169
+ # @return [When::TM::CalDate] date またはその直後のイベントの日時
170
+ alias :phase :event_eval
171
+
172
+ private
173
+
174
+ # 月の位相のための event_delta の別名
175
+ alias :phase_delta :event_delta
176
+
177
+ # オブジェクトの正規化
178
+ # num - 月の位相/12度の分子 (デフォルト 0 - )
179
+ # den - 月の位相/12度の分母 (デフォルト 30 - 1月)
180
+ # formula - 計算アルゴリズム(デフォルト '_ep:Formula?formula=1L')
181
+ # delta - enumerator の周期 (デフォルト (den/30)月)
182
+ # margin - 没滅計算用の補正 (デフォルト 1E-8)
183
+ def _normalize(args=[], options={})
184
+ num, den, formula, delta, margin = args
185
+ @event ||= 'phase'
186
+ @num = (num || @num || 0).to_f
187
+ @den = (den || @den || 30).to_f
188
+ @formula = When.Resource(formula || @formula ||'Formula?formula=1L', '_ep:')
189
+ @delta = When.Duration(delta || @delta || When::TM::IntervalLength.new(@den/30, 'month'))
190
+ @margin = (margin || @margin || 1E-8).to_f
191
+ super
192
+ end
193
+ end
194
+
195
+ #
196
+ # 天体暦の暦注
197
+ #
198
+ class Ephemeris < self
199
+
200
+ Notes = [When::BasicTypes::M17n, [
201
+ "locale:[=en:, ja=ja:, alias=ja:]",
202
+ "names:[Ephemeris]",
203
+
204
+ # 年の暦注 ----------------------------
205
+ [When::BasicTypes::M17n,
206
+ "names:[year]"
207
+ ],
208
+
209
+ # 月の暦注 ----------------------------
210
+ [When::BasicTypes::M17n,
211
+ "names:[month]",
212
+ [When::BasicTypes::M17n,
213
+ "names:[Month]"
214
+ ]
215
+ ],
216
+
217
+ # 日の暦注 ----------------------------
218
+ [When::BasicTypes::M17n,
219
+ "names:[day]",
220
+ "[Sunrise, 日の出 ]", # 日の出
221
+ "[Sunset, 日の入り ]", # 日の入り
222
+ [When::Coordinates::Residue,
223
+ "label:[Moon_Age=, 正午月齢=ja:%%<月齢>]",
224
+ "divisor:60",
225
+ "format:[%s(%4.1f)=]"
226
+ ],
227
+ "[Moonrise, 月の出 ]", # 月の出
228
+ "[Moonset=, 月の入り ]", # 月の入り
229
+ [When::BasicTypes::M17n,
230
+ "names:[Tide, 潮汐]", # 満潮干潮日時
231
+ "[High_Tide=en:Tide, 満潮=ja:%%<潮汐>]",
232
+ "[Low_Tide=en:Tide, 干潮=ja:%%<潮汐>]"
233
+ ]
234
+ ]
235
+ ]]
236
+
237
+ #
238
+ # 日の出
239
+ #
240
+ # @param [When::TM::TemporalPosition] date
241
+ # @param [Hash] options dummy
242
+ #
243
+ # @return [When::TM::TemporalPosition] 日の出の時刻をイベント時刻とする
244
+ #
245
+ def sunrise(date, options={})
246
+ event = formula(date.location.iri).sunrise(date)
247
+ event.events = [@root['Sunrise']]
248
+ event
249
+ rescue
250
+ nil
251
+ end
252
+
253
+ #
254
+ # 日の入り
255
+ #
256
+ # @param [When::TM::TemporalPosition] date
257
+ # @param [Hash] options dummy
258
+ #
259
+ # @return [When::TM::TemporalPosition] 日の入りの時刻をイベント時刻とする
260
+ #
261
+ def sunset(date, options={})
262
+ event = formula(date.location.iri).sunset(date)
263
+ event.events = [@root['Sunset']]
264
+ event
265
+ rescue
266
+ nil
267
+ end
268
+
269
+ #
270
+ # 正午月齢
271
+ #
272
+ # @param [When::TM::TemporalPosition] date
273
+ # @param [Hash] options dummy
274
+ #
275
+ # @return [Numeric] 正午における朔からの経過日数
276
+ #
277
+ def moon_age(date, options={})
278
+ @phase ||= When.CalendarNote('LunarPhases')
279
+ noon = date.floor(When::DAY,When::SYSTEM) + 0.5
280
+ @root['Moon_Age'][noon.to_f - @phase.phase(noon, [-30.0,30.0]).to_f]
281
+ end
282
+
283
+ #
284
+ # 月の出
285
+ #
286
+ # @param [When::TM::TemporalPosition] date
287
+ # @param [Hash] options dummy
288
+ #
289
+ # @return [When::TM::TemporalPosition] 月の出の時刻をイベント時刻とする
290
+ #
291
+ def moonrise(date, options={})
292
+ event = formula(date.location.iri).moonrise(date)
293
+ event.events = [@root['Moonrise']]
294
+ event
295
+ rescue
296
+ nil
297
+ end
298
+
299
+ #
300
+ # 月の入り
301
+ #
302
+ # @param [When::TM::TemporalPosition] date
303
+ # @param [Hash] options dummy
304
+ #
305
+ # @return [When::TM::TemporalPosition] 月の入りの時刻をイベント時刻とする
306
+ #
307
+ def moonset(date, options={})
308
+ event = formula(date.location.iri).moonset(date)
309
+ event.events = [@root['Moonset']]
310
+ event
311
+ rescue
312
+ nil
313
+ end
314
+
315
+ # 干潮・満潮の日時
316
+ #
317
+ # @param [When::TM::TemporalPosition] date
318
+ # @param [Hash] options 以下の通り
319
+ # @option options [String] tide 潮汐計算方式 'Horizontal' - 地平高度基準, 'Equatorial' - 子午線通過基準(デフォルト)
320
+ #
321
+ # @return [Array<Array<Integer, When::TM::TemporalPosotion>>] 干潮・満潮の日時の Array
322
+ #
323
+ # [Integer] +1:満潮, -1:干潮
324
+ #
325
+ # [When::TM::TemporalPosotion] 干潮・満潮の日時
326
+ #
327
+ #
328
+ def tide(date, options={})
329
+ return nil unless @interval
330
+ @target ||= When.Resource('_ep:Moon')
331
+ events = @root['Tide']
332
+ form = formula(date.location.iri)
333
+ type = options[:tide] =~ /\Ahorizon/i ? nil : 0
334
+
335
+ now = +date
336
+ high_tides = []
337
+ 5.times do |i|
338
+ high_tide = form.day_event(now + i - 2, type, @target) + @interval
339
+ high_tides << high_tide if high_tides.size == 0 || high_tide > high_tides[-1] + 0.5
340
+ end
341
+ tides = []
342
+
343
+ (high_tides.size-1).times do |i|
344
+ tides << [0, high_tides[i]]
345
+ tides << [1, 0.75*high_tides[i] + 0.25*high_tides[i+1]]
346
+ tides << [0, 0.50*high_tides[i] + 0.50*high_tides[i+1]]
347
+ tides << [1, 0.25*high_tides[i] + 0.75*high_tides[i+1]]
348
+ end
349
+ tides << [0, high_tides[-1]]
350
+
351
+ today = +date.floor(When::DAY)...+date.ceil(When::DAY)
352
+ seed = date._attr
353
+ seed[:clock] ||= When::TM::Clock.local_time
354
+ tides.select {|x| today.include?(x[1])}.map {|x|
355
+ d = form._to_seed_type(x[1], seed)
356
+ d.events = [events[x[0]]]
357
+ d
358
+ }
359
+ rescue
360
+ nil
361
+ end
362
+
363
+ private
364
+
365
+ # オブジェクトの正規化
366
+ # long - 計算に用いる経度 /
367
+ # lat - 計算に用いる緯度 /
368
+ # alt - 計算に用いる高度 / m
369
+ # interval - 高潮間隔(月の子午線通過から満潮までの時間) / 時間
370
+ def _normalize(args=[], options={})
371
+ if @location
372
+ @location = When.Resource(@location)
373
+ @formula = When.Resource(@formula || "Formula?location=(#{@location.iri})", '_ep:')
374
+ else
375
+ @formula = {}
376
+ end
377
+ @interval = @interval.sub('@','.').to_f / 24 if @interval
378
+ @root = When.CalendarNote('Ephemeris/Notes::day')
379
+ @prime ||= [%w(Month), %w(Sunrise Sunset Moon_Age)]
380
+ super
381
+ end
382
+
383
+ # 計算に用いる Ephemeris
384
+ def formula(location)
385
+ return @formula unless @formula.kind_of?(Hash)
386
+ @formula[location] ||= When.Resource("Formula?location=(#{location})", '_ep:')
387
+ end
388
+ end
389
+ end