ruby-ephemeris 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. checksums.yaml +7 -0
  2. data/lib/ephemeris.rb +336 -0
  3. metadata +52 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: dfc646687b8a3dbb654bd1d2f2e2b09e268fec7d9204fad4b63f7835b99d0157
4
+ data.tar.gz: 4a6b5b2bca82f971beeeb6ffff62141549054c3b13d59bf5ebe82fa564daab99
5
+ SHA512:
6
+ metadata.gz: 5d2f51a20fc76f4f2f75e16da7fd3dd6e65e17d53ea620d6925c7be24c2a501cd8a595aed5ed630d1f9d15f3c34cac635b340dc1479c8fcf34d371bc1d30ecae
7
+ data.tar.gz: fc43fc53d1a731e88d57d33e3a5d96eac5cec51e63757bc9b378134e1d21f9bfc07021221839846cc76efa9d9eb0ffa76049d0aabd57d74051c3fea40fb2a029
data/lib/ephemeris.rb ADDED
@@ -0,0 +1,336 @@
1
+ class Numeric
2
+ def deg
3
+ self * Math::PI / 180
4
+ end
5
+ def hms
6
+ hrs = self.to_i
7
+ m = ((self - hrs)*60).abs
8
+ min = m.to_i
9
+ sec = ((m - min)*60).to_i.abs
10
+ return hrs, min, sec
11
+ end
12
+ def to_hms
13
+ hrs, min, sec = self.hms
14
+ return "#{hrs.to_s.rjust(2, "0")}:#{min.to_s.rjust(2, "0")}:#{sec.to_s.rjust(2, "0")}"
15
+ end
16
+ end
17
+
18
+ class Ephemeris
19
+ attr_reader :sun, :moon, :mercury, :venus, :mars, :jupiter, :saturn, :uranus, :neptune
20
+
21
+ def body_data
22
+ @body = {
23
+ "sun" => {
24
+ "N" => 0.0,
25
+ "i" => 0.0,
26
+ "w" => 282.9404 + 4.70935e-5 * @d,
27
+ "a" => 1.000000,
28
+ "e" => 0.016709 - 1.151e-9 * @d,
29
+ "M" => 356.0470 + 0.98555 * @d},
30
+ #"M" => 356.0470 + 0.9856002585 * @d},
31
+ "moon" => {
32
+ "N" => 125.1228 - 0.0529538083 * @d,
33
+ "i" => 5.1454,
34
+ "w" => 318.0634 + 0.1643573223 * @d,
35
+ "a" => 60.2666,
36
+ "e" => 0.054900,
37
+ "M" => 115.3654 + 13.06478 * @d},
38
+ #"M" => 115.3654 + 13.0649929509 * @d},
39
+ "mercury" => {
40
+ "N" => 48.3313 + 3.24587e-5 * @d,
41
+ "i" => 7.0047 + 5.00e-8 * @d,
42
+ "w" => 29.1241 + 1.01444e-5 * @d,
43
+ "a" => 0.387098,
44
+ "e" => 0.205635 + 5.59e-10 * @d,
45
+ #"M" => 168.6562 + 4.09257 * @d},
46
+ "M" => 168.6562 + 4.0923344368 * @d},
47
+ "venus" => {
48
+ "N" => 76.6799 + 2.46590e-5 * @d,
49
+ "i" => 3.3946 + 2.75e-8 * @d,
50
+ "w" => 54.8910 + 1.38374e-5 * @d,
51
+ "a" => 0.723330,
52
+ "e" => 0.006773 - 1.302e-9 * @d,
53
+ #"M" => 48.0052 + 1.602206 * @d},
54
+ "M" => 48.0052 + 1.6021302244 * @d},
55
+ "mars" => {
56
+ "N" => 49.5574 + 2.11081e-5 * @d,
57
+ "i" => 1.8497 - 1.78e-8 * @d,
58
+ "w" => 286.5016 + 2.92961e-5 * @d,
59
+ "a" => 1.523688,
60
+ "e" => 0.093405 + 2.516e-9 * @d,
61
+ "M" => 18.6021 + 0.52398 * @d},
62
+ #"M" => 18.6021 + 0.5240207766 * @d},
63
+ "jupiter" => {
64
+ "N" => 100.4542 + 2.76854e-5 * @d,
65
+ "i" => 1.3030 - 1.557e-7 * @d,
66
+ "w" => 273.8777 + 1.64505e-5 * @d,
67
+ "a" => 5.20256,
68
+ "e" => 0.048498 + 4.469e-9 * @d,
69
+ "M" => 19.8950 + 0.083052 * @d},
70
+ #"M" => 19.8950 + 0.0830853001 * @d},
71
+ "saturn" => {
72
+ "N" => 113.6634 + 2.38980e-5 * @d,
73
+ "i" => 2.4886 - 1.081e-7 * @d,
74
+ "w" => 339.3939 + 2.97661e-5 * @d,
75
+ "a" => 9.55475,
76
+ "e" => 0.055546 - 9.499e-9 * @d,
77
+ "M" => 316.9670 + 0.03339 * @d},
78
+ #"M" => 316.9670 + 0.0334442282 * @d},
79
+ "uranus" => {
80
+ "N" => 74.0005 + 1.3978e-5 * @d,
81
+ "i" => 0.7733 + 1.9e-8 * @d,
82
+ "w" => 96.6612 + 3.0565e-5 * @d,
83
+ "a" => 19.18171 - 1.55e-8 * @d,
84
+ "e" => 0.047318 + 7.45e-9 * @d,
85
+ "M" => 142.5905 + 0.01168 * @d},
86
+ #"M" => 142.5905 + 0.011725806 * @d},
87
+ "neptune" => {
88
+ "N" => 131.7806 + 3.0173e-5 * @d,
89
+ "i" => 1.7700 - 2.55e-7 * @d,
90
+ "w" => 272.8461 - 6.027e-6 * @d,
91
+ "a" => 30.05826 + 3.313e-8 * @d,
92
+ "e" => 0.008606 + 2.15e-9 * @d,
93
+ "M" => 260.2471 + 0.005953 * @d}}
94
+ #"M" => 260.2471 + 0.005995147 * @d}}
95
+ end
96
+
97
+ def hms_dms(ra, dec) # Show HMS & DMS
98
+ h, m, s = (ra/15).hms
99
+ ra_hms = "#{h.to_s.rjust(2)}h #{m.to_s.rjust(2)}m #{s.to_s.rjust(2)}s"
100
+ d, m, s = dec.hms
101
+ dec_dms = "#{d.to_s.rjust(3)}° #{m.to_s.rjust(2)}´ #{s.to_s.rjust(2)}˝"
102
+ return ra_hms, dec_dms
103
+ end
104
+
105
+ def alt_az(ra, dec, time)
106
+ pi = Math::PI
107
+ ra_h = ra/15
108
+ #ha = (@sidtime - ra_h)*15
109
+ ha = (time - ra_h)*15
110
+ x = Math.cos(ha.deg) * Math.cos(dec.deg)
111
+ y = Math.sin(ha.deg) * Math.cos(dec.deg)
112
+ z = Math.sin(dec.deg)
113
+ xhor = x * Math.sin(@lat.deg) - z * Math.cos(@lat.deg)
114
+ yhor = y
115
+ zhor = x * Math.cos(@lat.deg) + z * Math.sin(@lat.deg)
116
+ az = Math.atan2(yhor, xhor)*180/pi + 180
117
+ alt = Math.asin(zhor)*180/pi
118
+ return alt, az
119
+ end
120
+
121
+ def body_alt_az(body, time)
122
+ self.alt_az(self.body_calc(body)[0], self.body_calc(body)[1], time)
123
+ end
124
+
125
+ def rts(ra, dec)
126
+ pi = Math::PI
127
+ transit = (ra - @ls - @lon)/15 + 12 + @tz
128
+ transit = (transit + 24) % 24
129
+ cos_lha = (-Math.sin(@lat.deg) * Math.sin(dec.deg)) / (Math.cos(@lat.deg) * Math.cos(dec.deg))
130
+ if cos_lha < -1
131
+ rise = "always"
132
+ set = "never"
133
+ elsif cos_lha > 1
134
+ rise = "never"
135
+ set = "always"
136
+ else
137
+ lha = Math.acos(cos_lha) * 180/pi
138
+ lha_h = lha/15
139
+ rise = ((transit - lha_h + 24) % 24).to_hms
140
+ set = ((transit + lha_h + 24) % 24).to_hms
141
+ end
142
+ trans = transit.to_hms
143
+ return rise, trans, set
144
+ end
145
+
146
+ def print
147
+
148
+ def distf(d)
149
+ int = d.to_i.to_s.rjust(2)
150
+ f = d % 1
151
+ frc = "%.4f" % f
152
+ return int + frc[1..5]
153
+ end
154
+
155
+ out = "Planet │ RA │ Dec │ Dist. │ Rise │ Trans │ Set \n"
156
+ out += "────────┼─────────────┼──────────────┼───────┼───────┼───────┼────── \n"
157
+
158
+ #["sun", "moon", "mercury", "venus", "mars", "jupiter", "saturn", "uranus", "neptune"].each do |p|
159
+ ["mercury", "venus", "mars", "jupiter", "saturn", "uranus", "neptune"].each do |p|
160
+ o = self.body_calc(p)
161
+ n_o = (p[0].upcase + p[1..]).ljust(7)
162
+ ra_o = o[3].ljust(11)
163
+ dec_o = o[4].ljust(12)
164
+ d_o = distf(o[2])[0..-3]
165
+ ris_o = o[5][0..-4].rjust(5)
166
+ tra_o = o[6][0..-4].rjust(5)
167
+ set_o = o[7][0..-4].rjust(5)
168
+
169
+ out += "#{n_o } │ #{ra_o } │ #{dec_o } │ #{d_o } │ #{ris_o} │ #{tra_o} │ #{set_o} \n"
170
+ end
171
+ return out
172
+ end
173
+
174
+ def initialize (date, lat, lon, tz)
175
+ pi = Math::PI
176
+
177
+ def get_vars(body) # GET VARIABLES FOR THE BODY
178
+ b = @body[body]
179
+ return b["N"], b["i"], b["w"], b["a"], b["e"], b["M"]
180
+ end
181
+
182
+ def body_calc(body) # CALCULATE FOR THE BODY
183
+ pi = Math::PI
184
+ n_b, i_b, w_b, a_b, e_b, m_b = self.get_vars(body)
185
+ w_b = (w_b + 360) % 360
186
+ m_b = m_b % 360
187
+ e1 = m_b + (180/pi) * e_b * Math.sin(m_b.deg) * (1 + e_b*Math.cos(m_b.deg))
188
+ e0 = 0
189
+ while (e1 - e0).abs > 0.0005
190
+ e0 = e1
191
+ e1 = e0 - (e0 - (180/pi) * e_b * Math.sin(e0.deg) - m_b) / (1 - e_b * Math.cos(e0.deg))
192
+ end
193
+ e = e1
194
+ x = a_b * (Math.cos(e.deg) - e_b)
195
+ y = a_b * Math.sqrt(1 - e_b*e_b) * Math.sin(e.deg)
196
+ r = Math.sqrt(x*x + y*y)
197
+ v = (Math.atan2(y, x)*180/pi + 360) % 360
198
+ xeclip = r * (Math.cos(n_b.deg) * Math.cos((v+w_b).deg) - Math.sin(n_b.deg) * Math.sin((v+w_b).deg) * Math.cos(i_b.deg))
199
+ yeclip = r * (Math.sin(n_b.deg) * Math.cos((v+w_b).deg) + Math.cos(n_b.deg) * Math.sin((v+w_b).deg) * Math.cos(i_b.deg))
200
+ zeclip = r * Math.sin((v+w_b).deg) * Math.sin(i_b.deg)
201
+ lon = (Math.atan2(yeclip, xeclip)*180/pi + 360) % 360
202
+ lat = Math.atan2(zeclip, Math.sqrt(xeclip*xeclip + yeclip*yeclip))*180/pi
203
+ r_b = Math.sqrt(xeclip*xeclip + yeclip*yeclip + zeclip*zeclip)
204
+ m_J = @body["jupiter"]["M"]
205
+ m_S = @body["saturn"]["M"]
206
+ m_U = @body["uranus"]["M"]
207
+ plon = 0
208
+ plat = 0
209
+ pdist = 0
210
+ case body
211
+ when "moon"
212
+ lb = (n_b + w_b + m_b) % 360
213
+ db = (lb - @ls + 360) % 360
214
+ fb = (lb - n_b + 360) % 360
215
+ plon += -1.274 * Math.sin((m_b - 2*db).deg)
216
+ plon += 0.658 * Math.sin((2*db).deg)
217
+ plon += -0.186 * Math.sin(@ms.deg)
218
+ plon += -0.059 * Math.sin((2*m_b - 2*db).deg)
219
+ plon += -0.057 * Math.sin((m_b - 2*db + @ms).deg)
220
+ plon += 0.053 * Math.sin((m_b + 2*db).deg)
221
+ plon += 0.046 * Math.sin((2*db - @ms).deg)
222
+ plon += 0.041 * Math.sin((m_b - @ms).deg)
223
+ plon += -0.035 * Math.sin(db.deg)
224
+ plon += -0.031 * Math.sin((m_b + @ms).deg)
225
+ plon += -0.015 * Math.sin((2*fb - 2*db).deg)
226
+ plon += 0.011 * Math.sin((m_b - 4*db).deg)
227
+ plat += -0.173 * Math.sin((fb - 2*db).deg)
228
+ plat += -0.055 * Math.sin((m_b - fb - 2*db).deg)
229
+ plat += -0.046 * Math.sin((m_b + fb - 2*db).deg)
230
+ plat += 0.033 * Math.sin((fb + 2*db).deg)
231
+ plat += 0.017 * Math.sin((2*m_b + fb).deg)
232
+ pdist += -0.58 * Math.cos((m_b - 2*db).deg)
233
+ pdist += -0.46 * Math.cos(2*db.deg)
234
+ when "jupiter"
235
+ plon += -0.332 * Math.sin((2*m_J - 5*m_S - 67.6).deg)
236
+ plon += -0.056 * Math.sin((2*m_J - 2*m_S + 21).deg)
237
+ plon += 0.042 * Math.sin((3*m_J - 5*m_S + 21).deg)
238
+ plon += -0.036 * Math.sin((m_J - 2*m_S).deg)
239
+ plon += 0.022 * Math.cos((m_J - m_S).deg)
240
+ plon += 0.023 * Math.sin((2*m_J - 3*m_S + 52).deg)
241
+ plon += -0.016 * Math.sin((m_J - 5*m_S - 69).deg)
242
+ when "saturn"
243
+ plon += 0.812 * Math.sin((2*m_J - 5*m_S - 67.6).deg)
244
+ plon += -0.229 * Math.cos((2*m_J - 4*m_S - 2).deg)
245
+ plon += 0.119 * Math.sin((m_J - 2*m_S - 3).deg)
246
+ plon += 0.046 * Math.sin((2*m_J - 6*m_S - 69).deg)
247
+ plon += 0.014 * Math.sin((m_J - 3*m_S + 32).deg)
248
+ plat += -0.020 * Math.cos((2*m_J - 4*m_S - 2).deg)
249
+ plat += 0.018 * Math.sin((2*m_J - 6*m_S - 49).deg)
250
+ when "uranus"
251
+ plon += 0.040 * Math.sin((m_S - 2*m_U + 6).deg)
252
+ plon += 0.035 * Math.sin((m_S - 3*m_U + 33).deg)
253
+ plon += -0.015 * Math.sin((m_J - m_U + 20).deg)
254
+ end
255
+ lon += plon
256
+ lat += plat
257
+ r_b += pdist
258
+ if body == "moon"
259
+ xeclip = Math.cos(lon.deg) * Math.cos(lat.deg)
260
+ yeclip = Math.sin(lon.deg) * Math.cos(lat.deg)
261
+ zeclip = Math.sin(lat.deg)
262
+ else
263
+ xeclip += @xs
264
+ yeclip += @ys
265
+ end
266
+ xequat = xeclip
267
+ yequat = yeclip * Math.cos(@ecl.deg) - zeclip * Math.sin(@ecl.deg)
268
+ zequat = yeclip * Math.sin(@ecl.deg) + zeclip * Math.cos(@ecl.deg)
269
+ ra = (Math.atan2(yequat, xequat)*180/pi + 360) % 360
270
+ dec = Math.atan2(zequat, Math.sqrt(xequat*xequat + yequat*yequat))*180/pi
271
+ body == "moon" ? par = Math.asin(1/r_b)*180/pi : par = (8.794/3600)/r_b
272
+ gclat = @lat - 0.1924 * Math.sin(2*@lat.deg)
273
+ rho = 0.99833 + 0.00167 * Math.cos(2*@lat.deg)
274
+ lst = @sidtime * 15
275
+ ha = (lst - ra + 360) % 360
276
+ g = Math.atan(Math.tan(gclat.deg) / Math.cos(ha.deg))*180/pi
277
+ topRA = ra - par * rho * Math.cos(gclat.deg) * Math.sin(ha.deg) / Math.cos(dec.deg)
278
+ topDecl = dec - par * rho * Math.sin(gclat.deg) * Math.sin((g - dec).deg) / Math.sin(g.deg)
279
+ ra = topRA.round(4)
280
+ dec = topDecl.round(4)
281
+ r = Math.sqrt(xequat*xequat + yequat*yequat + zequat*zequat).round(4)
282
+ ri, tr, se = self.rts(ra, dec)
283
+ object = [ra, dec, r, self.hms_dms(ra, dec), ri, tr, se].flatten
284
+ return object
285
+ end
286
+
287
+ # START OF INITIALIZE
288
+ @lat = lat
289
+ @lon = lon
290
+ @tz = tz
291
+ y = date[0..3].to_i
292
+ m = date[5..6].to_i
293
+ d = date[8..9].to_i
294
+ @d = 367*y - 7*(y + (m+9)/12) / 4 + 275*m/9 + d - 730530
295
+ @ecl = 23.4393 - 3.563E-7*@d
296
+
297
+ self.body_data
298
+
299
+ # SUN
300
+ n_s, i_s, w_s, a_s, e_s, m_s = self.get_vars("sun")
301
+ w_s = (w_s + 360) % 360
302
+ @ms = m_s % 360
303
+ es = @ms + (180/pi) * e_s * Math.sin(@ms.deg) * (1 + e_s*Math.cos(@ms.deg))
304
+ x = Math.cos(es.deg) - e_s
305
+ y = Math.sin(es.deg) * Math.sqrt(1 - e_s*e_s)
306
+ v = Math.atan2(y,x)*180/pi
307
+ r = Math.sqrt(x*x + y*y)
308
+ tlon = (v + w_s)%360
309
+ @xs = r * Math.cos(tlon.deg)
310
+ @ys = r * Math.sin(tlon.deg)
311
+ xe = @xs
312
+ ye = @ys * Math.cos(@ecl.deg)
313
+ ze = @ys * Math.sin(@ecl.deg)
314
+ r = Math.sqrt(xe*xe + ye*ye + ze*ze)
315
+ ra = Math.atan2(ye,xe)*180/pi
316
+ ra_s = ((ra + 360)%360).round(4)
317
+ dec_s = (Math.atan2(ze,Math.sqrt(xe*xe + ye*ye))*180/pi).round(4)
318
+
319
+ @ls = (w_s + @ms)%360
320
+ gmst0 = (@ls + 180)/15%24
321
+ @sidtime = gmst0 + @lon/15
322
+
323
+ @alt_s, @az_s = self.alt_az(ra_s, dec_s, @sidtime)
324
+
325
+ @sun = [ra_s, dec_s, 1.0, self.hms_dms(ra_s, dec_s)].flatten
326
+ @moon = self.body_calc("moon")
327
+ @mercury = self.body_calc("mercury")
328
+ @venus = self.body_calc("venus")
329
+ @mars = self.body_calc("mars")
330
+ @jupiter = self.body_calc("jupiter")
331
+ @saturn = self.body_calc("saturn")
332
+ @uranus = self.body_calc("uranus")
333
+ @neptune = self.body_calc("neptune")
334
+
335
+ end
336
+ end
metadata ADDED
@@ -0,0 +1,52 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby-ephemeris
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Geir Isene
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-09-25 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: "Usage is simple and straightforward:\n\no = Ephemeris.new(date, lat,
14
+ lon, tz)\n...creates a new ephemeris object for the \"date\" (a string in ISO format
15
+ 2020-12-16) by supplying the observer latitude (lat), longitude (lon) and time zone
16
+ (tz).\n\nExample: today = Ephemeris.new(\"2020-12-16\", 59.568, 10.02, 1)\n\nYou
17
+ will then have access to the following data:\n\ntoday.sun\ntoday.moon \ntoday.mercury\ntoday.venus\ntoday.mars\ntoday.jupiter\ntoday.saturn\ntoday.uranus\ntoday.neptune\nBy
18
+ calling any of these, you will get back an array with the following data:\n\n[ra,
19
+ dec, distance, ra_string, dec_string, rise, transit, set]\n\nSee Github page for
20
+ more info: https://github.com/isene/ephemeris"
21
+ email: g@isene.com
22
+ executables: []
23
+ extensions: []
24
+ extra_rdoc_files: []
25
+ files:
26
+ - lib/ephemeris.rb
27
+ homepage: https://isene.com/
28
+ licenses:
29
+ - Unlicense
30
+ metadata:
31
+ source_code_uri: https://github.com/isene/ephemeris
32
+ post_install_message:
33
+ rdoc_options: []
34
+ require_paths:
35
+ - lib
36
+ required_ruby_version: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ required_rubygems_version: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ requirements: []
47
+ rubygems_version: 3.1.2
48
+ signing_key:
49
+ specification_version: 4
50
+ summary: Ephemeris class for Ruby. Sun, Moon and planet positions. Rise, tranist,
51
+ set times.
52
+ test_files: []