solar 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/Gemfile ADDED
@@ -0,0 +1,13 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem "activesupport", ">= 2.3.5"
5
+
6
+ # Add dependencies to develop your gem here.
7
+ # Include everything needed to run rake, tests, features, etc.
8
+ group :development do
9
+ gem "shoulda", ">= 0"
10
+ gem "rdoc", "~> 3.12"
11
+ gem "bundler", "~> 1"
12
+ gem "jeweler", "~> 1.8.4"
13
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,33 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ activesupport (3.2.8)
5
+ i18n (~> 0.6)
6
+ multi_json (~> 1.0)
7
+ git (1.2.5)
8
+ i18n (0.6.1)
9
+ jeweler (1.8.4)
10
+ bundler (~> 1.0)
11
+ git (>= 1.2.5)
12
+ rake
13
+ rdoc
14
+ json (1.7.5)
15
+ multi_json (1.3.6)
16
+ rake (0.9.2.2)
17
+ rdoc (3.12)
18
+ json (~> 1.4)
19
+ shoulda (3.1.1)
20
+ shoulda-context (~> 1.0)
21
+ shoulda-matchers (~> 1.2)
22
+ shoulda-context (1.0.0)
23
+ shoulda-matchers (1.3.0)
24
+ activesupport (>= 3.0.0)
25
+
26
+ PLATFORMS
27
+ ruby
28
+
29
+ DEPENDENCIES
30
+ bundler (~> 1)
31
+ jeweler (~> 1.8.4)
32
+ rdoc (~> 3.12)
33
+ shoulda
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Javier Goizueta
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,19 @@
1
+ = solar
2
+
3
+ Calculation of solar position, rise & set times for a given position & time.
4
+
5
+ == Contributing to solar
6
+
7
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
8
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
9
+ * Fork the project.
10
+ * Start a feature/bugfix branch.
11
+ * Commit and push until you are happy with your contribution.
12
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
13
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
14
+
15
+ == Copyright
16
+
17
+ Copyright (c) 2012 Javier Goizueta. See LICENSE.txt for
18
+ further details.
19
+
data/Rakefile ADDED
@@ -0,0 +1,45 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "solar"
18
+ gem.homepage = "http://github.com/jgoizueta/solar"
19
+ gem.license = "MIT"
20
+ gem.summary = %Q{# Calculation of solar position, rise & set times}
21
+ gem.description = %Q{# Calculation of solar position, rise & set times for a given position & time.}
22
+ gem.email = "jgoizueta@gmail.com"
23
+ gem.authors = ["Javier Goizueta"]
24
+ # dependencies defined in Gemfile
25
+ end
26
+ Jeweler::RubygemsDotOrgTasks.new
27
+
28
+ require 'rake/testtask'
29
+ Rake::TestTask.new(:test) do |test|
30
+ test.libs << 'lib' << 'test'
31
+ test.pattern = 'test/**/test_*.rb'
32
+ test.verbose = true
33
+ end
34
+
35
+ task :default => :test
36
+
37
+ require 'rdoc/task'
38
+ Rake::RDocTask.new do |rdoc|
39
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
40
+
41
+ rdoc.rdoc_dir = 'rdoc'
42
+ rdoc.title = "solar #{version}"
43
+ rdoc.rdoc_files.include('README*')
44
+ rdoc.rdoc_files.include('lib/**/*.rb')
45
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
data/lib/solar.rb ADDED
@@ -0,0 +1,443 @@
1
+ # Calculation of solar position, rise & set times for a given position & time.
2
+ # Algorithms are taken from Jean Meeus, Astronomical Algorithms
3
+ # Some code & ideas taken from John P. Power's astro-algo: http://astro-algo.rubyforge.org/astro-algo/
4
+ module Solar
5
+
6
+ ALTITUDES = {
7
+ :official => -50/60.0,
8
+ :civil => -6.0,
9
+ :nautical => -12.0,
10
+ :astronomical => -18.0
11
+ }
12
+
13
+ class <<self
14
+
15
+ # Day-night (or twilight) status at a given position and time
16
+ # returns :night, :day or :twilight
17
+ # options:
18
+ # * :twilight_zenith zenith for the sun at dawn (beginning of twilight)
19
+ # and at dusk (end of twilight). Default: :civil
20
+ # * :day_zenith zenith for the san at sunrise and sun set.
21
+ # Default: :official (sun aparently under the horizon, tangent to it)
22
+ # These parameters can be assigned zenith values in degrees of the symbols:
23
+ # :official, :civil, :nautical or :astronomical.
24
+ def day_or_night(t, longitude, latitude, options={})
25
+ if options[:zenith]
26
+ twilight_altitude = day_altitude = altitude_from_options(options)
27
+ else
28
+ twilight_altitude = altitude_from_options(:zenith => options[:twilight_zenith] || :civil)
29
+ day_altitude = altitude_from_options(:zenith => options[:day_zenith] || :official)
30
+ end
31
+ al,az = position(t, longitude, latitude)
32
+ (al > day_altitude) ? :day : (al <= twilight_altitude) ? :night : :twilight
33
+ end
34
+
35
+ # Sun horizontal coordinates (relative position) in degrees:
36
+ # * elevation (altitude over horizon) in degrees; positive upwards
37
+ # * azimuth in degrees measured clockwise (towards East) from North direction
38
+ def position(t, longitude, latitude)
39
+
40
+ delta_rad, alpha_rad = equatorial_position_rad(t)
41
+ alpha_deg = to_deg(alpha_rad)
42
+ # alpha_h += 360 if alpha_h < 0
43
+
44
+
45
+ # t as Julian centuries of 36525 ephemeris days form the epoch J2000.0
46
+ if false
47
+ # Float
48
+ jd = jd_f(t)
49
+ else
50
+ # Rational
51
+ jd = jd_r(t)
52
+ end
53
+ t = to_jc(jd)
54
+
55
+ # Sidereal time at Greenwich
56
+ theta = 280.46061837 + 360.98564736629*(jd-2451545) + (0.000387933 - t/38710000)*t*t
57
+
58
+ # Reduce magnitude to minimize errors
59
+ theta %= 360
60
+
61
+ # Local hour angle
62
+ h = theta + longitude - alpha_deg
63
+ h %= 360
64
+
65
+ latitude_rad = to_rad(latitude)
66
+ h_rad = to_rad(h)
67
+
68
+ # Local horizontal coordinates : Meeus pg 89
69
+ altitude_rad = Math.asin(Math.sin(latitude_rad)*Math.sin(delta_rad) + Math.cos(latitude_rad)*Math.cos(delta_rad)*Math.cos(h_rad))
70
+ azimuth_rad = Math.atan2((Math.sin(h_rad)),((Math.cos(h_rad) * Math.sin(latitude_rad)) - Math.tan(delta_rad) * Math.cos(latitude_rad)))
71
+
72
+ [to_deg(altitude_rad), (180+to_deg(azimuth_rad))%360 ]
73
+
74
+ end
75
+
76
+ # Sun rise time for a given date (UTC) and position.
77
+ # The :zenith or :altitude of the sun can be passed as an argument,
78
+ # which can be numeric (in degrees) or symbolic:
79
+ # :official, :civil, :nautical or :astronomical.
80
+ # nil is returned if the sun doesn't rise at the date and position.
81
+ def rise(date, longitude, latitude, options={})
82
+ rising, transit, setting = passages(date, longitude, latitude, options)
83
+ if rising==setting || (setting-rising)==1
84
+ nil # rising==setting => no rise; setting-rising == 1 => no set
85
+ else
86
+ rising
87
+ end
88
+ end
89
+
90
+ # Sun set time for a given date (UTC) and position.
91
+ # The :zenith or :altitude of the sun can be passed as an argument,
92
+ # which can be numeric (in degrees) or symbolic:
93
+ # :official, :civil, :nautical or :astronomical.
94
+ # nil is returned if the sun doesn't set at the date and position.
95
+ def set(date, longitude, latitude, options={})
96
+ rising, transit, setting = passages(date, longitude, latitude, options)
97
+ if rising==setting || (setting-rising)==1
98
+ nil # rising==setting => no rise; setting-rising == 1 => no set
99
+ else
100
+ setting
101
+ end
102
+ end
103
+
104
+ # Rise and set times as given by rise() and set()
105
+ def rise_and_set(date, longitude, latitude, options={})
106
+ rising, transit, setting = passages(date, longitude, latitude, options)
107
+ if rising==setting || (setting-rising)==1
108
+ nil # rising==setting => no rise; setting-rising == 1 => no set
109
+ else
110
+ [rising, setting]
111
+ end
112
+ end
113
+
114
+ # Solar passages [rising, transit, setting] for a given date (UTC) and position.
115
+ # The :zenith or :altitude of the sun can be passed as an argument,
116
+ # which can be numeric (in degrees) or symbolic:
117
+ # :official, :civil, :nautical or :astronomical.
118
+ # In circumpolar case:
119
+ # If Sun never rises, returns 00:00:00 on Date for all passages.
120
+ # If Sun never sets, returns 00:00:00 (rising), 12:00:00 (transit), 24:00:00 (setting)
121
+ # on Date for all passages.
122
+ def passages(date, longitude, latitude, options={})
123
+
124
+ ho = altitude_from_options(options)
125
+ t = to_jc(jd_r(date.to_datetime))
126
+ theta0 = (100.46061837 + (36000.770053608 + (0.000387933 - t/38710000)*t)*t) % 360
127
+ # Calculate apparent right ascention and declination for 0 hr Dynamical time for three days (degrees)
128
+ ra = []
129
+ decl = []
130
+ -1.upto(1) do |i|
131
+ declination, right_ascention = equatorial_position_rad((date+i).to_datetime)
132
+ ra << to_deg(right_ascention)
133
+ decl << to_deg(declination)
134
+ end
135
+ # tweak right ascention around 180 degrees (autumnal equinox)
136
+ if ra[0] > ra[1]
137
+ ra[0] -= 360
138
+ end
139
+ if ra[2] < ra[1]
140
+ ra[2] += 360
141
+ end
142
+
143
+ ho_rad, latitude_rad = [ho, latitude].map{|x| to_rad(x)}
144
+ decl_rad = decl.map{|x| to_rad(x)}
145
+
146
+ # approximate Hour Angle (degrees)
147
+ ha = Math.sin(ho_rad) / (Math.cos(latitude_rad) * Math.cos(decl_rad[1])) - Math.tan(latitude_rad) * Math.tan(decl_rad[1])
148
+ # handle circumpolar. see note 2 at end of chapter
149
+ if ha.abs <= 1
150
+ ha = to_deg(Math.acos(ha))
151
+ elsif ha > 1 # circumpolar - sun never rises
152
+ # format sunrise, sunset & solar noon as DateTime
153
+ sunrise = date.to_datetime
154
+ transit = date.to_datetime
155
+ sunset = date.to_datetime
156
+ return [sunrise, transit, sunset]
157
+ else # cirumpolar - sun never sets
158
+ # format sunrise, sunset & solar noon as DateTime
159
+ sunrise = date.to_datetime
160
+ transit = date.to_datetime + 0.5
161
+ sunset = date.to_datetime + 1
162
+ return [sunrise, transit, sunset]
163
+ end
164
+ # approximate m (fraction of 1 day)
165
+ # store days added or subtracted to add in later
166
+ m = []
167
+ days = [0]*3
168
+ for i in 0..2
169
+ case i
170
+ when 0
171
+ m[i] = (ra[1] - longitude - theta0) / 360 # transit
172
+ day_offset = +1
173
+ when 1
174
+ m[i] = m[0] - ha / 360 # rising
175
+ day_offset = -1
176
+ when 2
177
+ m[i] = m[0] + ha / 360 # setting
178
+ day_offset = -1
179
+ end
180
+
181
+ until m[i] >= 0 do
182
+ m[i] += 1
183
+ days[i] += day_offset
184
+ end
185
+ until m[i] <= 1 do
186
+ m[i] -= 1
187
+ days[i] -= day_offset
188
+ end
189
+ end
190
+ theta = [] # apparent sidereal time (degrees)
191
+ ra2 = [] # apparent right ascension (degrees)
192
+ decl2 = [] # apparent declination (degrees)
193
+ h = [] # local hour angle (degrees)
194
+ alt = [] # altitude (degrees)
195
+ delta_m = [1]*3
196
+ while ( delta_m[0] >= 0.01 || delta_m[1] >= 0.01 || delta_m[2] >= 0.01 ) do
197
+ 0.upto(2) do |i|
198
+ theta[i] = theta0 + 360.985647 * m[i]
199
+ n = m[i] + delta_t(date.to_datetime).to_r / 86400
200
+ a = ra[1] - ra[0]
201
+ b = ra[2] - ra[1]
202
+ c = b - a
203
+ ra2[i] = ra[1] + n / 2 * ( a + b + n * c )
204
+
205
+ n = m[i] + delta_t(date.to_datetime).to_r / 86400
206
+ a = decl[1] - decl[0]
207
+ b = decl[2] - decl[1]
208
+ c = b - a
209
+ decl2[i] = decl[1] + n / 2 * ( a + b + n * c )
210
+
211
+ h[i] = theta[i] + longitude - ra2[i]
212
+
213
+ alt[i] = to_deg Math.asin(Math.sin(latitude_rad) * Math.sin(to_rad(decl2[i])) +
214
+ Math.cos(latitude_rad) * Math.cos(to_rad(decl2[i])) * Math.cos(to_rad(h[i])))
215
+ end
216
+ # adjust m
217
+ delta_m[0] = -h[0] / 360
218
+ 1.upto(2) do |i|
219
+ delta_m[i] = (alt[i] - ho) / (360 * Math.cos(to_rad(decl2[i])) * Math.cos(latitude_rad) * Math.sin(to_rad(h[i])))
220
+ end
221
+ 0.upto(2) do |i|
222
+ m[i] += delta_m[i]
223
+ end
224
+ end
225
+ # format sunrise, sunset & solar noon as DateTime
226
+ sunrise = date.to_datetime + m[1] + days[1]
227
+ transit = date.to_datetime + m[0] + days[0]
228
+ sunset = date.to_datetime + m[2] + days[2]
229
+ [sunrise, transit, sunset]
230
+ end
231
+
232
+
233
+ private
234
+
235
+ # Julian Day as Rational
236
+ def jd_r(t)
237
+ if false
238
+ # This computes JD with precision of seconds and yields smaller denominators
239
+ t = t.utc
240
+ t.to_date.ajd + Rational(t.hour,24) + Rational(t.min,1440) + Rational(t.sec,86400)
241
+ else
242
+ # This preserves the internal precision of t (which we probably don't need)
243
+ # and produces larger denominators in general
244
+ t.to_datetime.utc.ajd
245
+ end
246
+ end
247
+
248
+ # Julian Day as Float
249
+ def jd_f(t)
250
+ # t.to_date.ajd.to_f + t.hour/24.0 + t.min/1440.0 + t.sec/86400.0
251
+ t.to_datetime.utc.ajd.to_f
252
+ end
253
+
254
+ def to_rad(deg)
255
+ deg*Math::PI/180.0
256
+ end
257
+
258
+ def to_deg(rad)
259
+ rad*180.0/Math::PI
260
+ end
261
+
262
+ def to_h(deg)
263
+ deg/15.0
264
+ end
265
+
266
+ # Julian day to Julian Centuries since J2000.0
267
+ def to_jc(jd)
268
+ (jd - 2451545)/36525
269
+ end
270
+
271
+ def polynomial(coefficients, x)
272
+ coefficients.inject(0.0){|p, a| p*x + a}
273
+ end
274
+
275
+ # Conversion of Float to Rational preserving the exact value of the number
276
+ def to_r(x)
277
+ x = x.to_f
278
+ return Rational(x.to_i,1) if x.modulo(1)==0
279
+ if !x.finite?
280
+ return Rational(0,0) if x.nan?
281
+ return x<0 ? Rational(-1,0) : Rational(1,0)
282
+ end
283
+
284
+ f,e = Math.frexp(x)
285
+
286
+ if e < Float::MIN_EXP
287
+ bits = e+Float::MANT_DIG-Float::MIN_EXP
288
+ else
289
+ bits = [Float::MANT_DIG,e].max
290
+ #return Rational(x.to_i,1) if bits<e
291
+ end
292
+ p = Math.ldexp(f,bits)
293
+ e = bits - e
294
+ if e<Float::MAX_EXP
295
+ q = Math.ldexp(1,e)
296
+ else
297
+ q = Float::RADIX**e
298
+ end
299
+ return Rational(p.to_i,q.to_i)
300
+ end
301
+
302
+ # time to dynamical time
303
+ def to_td(t)
304
+ t = t.utc
305
+ t + to_r(delta_t(t))/86400
306
+ end
307
+
308
+ # dynamical_time to utc
309
+ def to_utc(td)
310
+ raise "Invalid dynamical time (should be utc)" unless td.utc?
311
+ td - to_r(delta_t(td))/86400
312
+
313
+ end
314
+
315
+ # Compute difference between dynamical time and UTC in seconds.
316
+ # See http://sunearth.gsfc.nasa.gov/eclipse/SEcat5/deltatpoly.html.
317
+ # Good from -1999 to +3000.
318
+ def delta_t(date)
319
+
320
+ year = date.year.to_f
321
+ y = year + (date.month.to_f - 0.5) / 12.0
322
+
323
+ case
324
+ when year < -500.0
325
+ u = (year - 1820.0) / 100.0
326
+ -20.0 + 32.0*u*u
327
+ when year < 500.0
328
+ u = y / 100.0
329
+ polynomial [0.0090316521, 0.022174192, -0.1798452, -5.952053, 33.78311, -1014.41, 10583.6], u
330
+ when year < 1600.0
331
+ u = (y - 1000.0) / 100.0
332
+ polynomial [0.0083572073, -0.005050998, -0.8503463, 0.319781, 71.23472, -556.01, 1574.2], u
333
+ when year < 1700.0
334
+ t = y - 1600.0
335
+ polynomial [1.0/7129.0, -0.01532, -0.9808, 120.0], t
336
+ when year < 1800.0
337
+ t = y - 1700.0
338
+ polynomial [-1.0/1174000.0, 0.00013336, -0.0059285, 0.1603, 8.83], t
339
+ when year < 1860.0
340
+ t = y - 1800.0
341
+ polynomial [0.000000000875, -0.0000001699, 0.0000121272, -0.00037436, 0.0041116, 0.0068612, -0.332447, 13.72], t
342
+ when year < 1900.0
343
+ t = y - 1860.0
344
+ polynomial [1.0/233174.0, -0.0004473624, 0.01680668, -0.251754, 0.5737, 7.62], t
345
+ when year < 1920.0
346
+ t = y - 1900.0
347
+ polynomial [-0.000197, 0.0061966, -0.0598939, 1.494119, -2.79], t
348
+ when year < 1941.0
349
+ t = y - 1920.0
350
+ polynomial [0.0020936, -0.076100, 0.84493, 21.20], t
351
+ when year < 1961.0
352
+ t = y - 1950.0
353
+ polynomial [1.0/2547.0, -1.0/233.0, 0.407, 29.07], t
354
+ when year < 1986.0
355
+ t = y - 1975.0
356
+ polynomial [-1.0/718.0, -1.0/260.0, 1.067, 45.45], t
357
+ when year < 2005.0
358
+ t = y - 2000.0
359
+ polynomial [0.00002373599, 0.000651814, 0.0017275, -0.060374, 0.3345, 63.86], t
360
+ when year < 2050.0
361
+ t = y - 2000.0
362
+ polynomial [0.005589, 0.32217, 62.92], t
363
+ when year < 2150.0
364
+ -20.0 + 32.0*((y - 1820.0)/100.0)**2 - 0.5628*(2150.0 - y)
365
+ else
366
+ u = (year - 1820.0) / 100.0
367
+ -20.0 + 32*u*u
368
+ end
369
+ end
370
+
371
+ # Solar equatorial coordinates / Low accuracy : Meeus pg 151
372
+ # returns [declination in radians, right ascension in radians]
373
+ def equatorial_position_rad(t)
374
+ # t as Julian centuries of 36525 ephemeris days form the epoch J2000.0
375
+ if false
376
+ # Float
377
+ jd = jd_f(to_td(t))
378
+ else
379
+ # Rational
380
+ jd = jd_r(to_td(t))
381
+ end
382
+ t = to_jc(jd)
383
+
384
+ # Geometric mean longitude of the Sun, referred to the mean equinox of the date
385
+ l = 280.46645 + (36000.76983 + 0.0003032*t)*t
386
+
387
+ # Mean anomaly of the Sun
388
+ m_deg = 357.52910 + (35999.05030 - (0.0001559 + 0.00000048*t)*t)*t
389
+ m_rad = to_rad(m_deg)
390
+
391
+ # Eccentricity of the Earth's orbit
392
+ e = 0.016708617 - (0.000042037 + 0.0000001236*t)*t
393
+
394
+ # Sun's Equation of the center
395
+ c = (1.914600 - (0.004817 + 0.000014*t)*t)*Math.sin(m_rad) + (0.019993 - 0.000101*t)*Math.sin(2*m_rad) + 0.000290*Math.sin(3*m_rad)
396
+
397
+ # Sun's true longitude
398
+ o = l + c
399
+
400
+ # Reduce magnitude to minimize errors
401
+ o %= 360
402
+
403
+ # Sun's apparent Longitude
404
+ omega_deg = 125.04 - 1934.136*t
405
+ omega_rad = to_rad(omega_deg)
406
+ lambda_deg = o - 0.00569 - 0.00478 * Math.sin(omega_rad)
407
+
408
+ # Reduce magnitude to minimize errors
409
+ lambda_deg %= 360
410
+
411
+ lambda_rad = to_rad(lambda_deg)
412
+
413
+ # Obliquity of the ecliptic
414
+ epsilon_deg = 23.4392966666667 - (0.012777777777777778 + (0.00059/60 - 0.00059/60*t)*t)*t + 0.00256*Math.cos(omega_rad)
415
+ epsilon_rad = to_rad(epsilon_deg)
416
+
417
+ # Sun's declination
418
+ delta_rad = Math.asin(Math.sin(epsilon_rad)*Math.sin(lambda_rad))
419
+
420
+ # Sun's right ascension
421
+ alpha_rad = Math.atan2(((Math.cos(epsilon_rad) * Math.sin(lambda_rad))),(Math.cos(lambda_rad)))
422
+
423
+ [delta_rad, alpha_rad]
424
+ end
425
+
426
+ def altitude_from_options(options)
427
+ if options.has_key?(:zenith)
428
+ zenith = options[:zenith]
429
+ if Symbol===zenith
430
+ altitude = ALTITUDES[zenith]
431
+ else
432
+ altitude = 90.0 - zenith
433
+ end
434
+ else
435
+ altitude = options[:altitude] || :official
436
+ altitude = ALTITUDES[altitude] if Symbol===altitude
437
+ end
438
+ altitude
439
+ end
440
+
441
+ end
442
+
443
+ end
data/solar.gemspec ADDED
@@ -0,0 +1,59 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "solar"
8
+ s.version = "0.0.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Javier Goizueta"]
12
+ s.date = "2012-10-07"
13
+ s.description = "# Calculation of solar position, rise & set times for a given position & time."
14
+ s.email = "jgoizueta@gmail.com"
15
+ s.extra_rdoc_files = [
16
+ "LICENSE.txt",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ "Gemfile",
22
+ "Gemfile.lock",
23
+ "LICENSE.txt",
24
+ "README.rdoc",
25
+ "Rakefile",
26
+ "VERSION",
27
+ "lib/solar.rb",
28
+ "solar.gemspec",
29
+ "test/helper.rb",
30
+ "test/test_solar.rb"
31
+ ]
32
+ s.homepage = "http://github.com/jgoizueta/solar"
33
+ s.licenses = ["MIT"]
34
+ s.require_paths = ["lib"]
35
+ s.rubygems_version = "1.8.23"
36
+ s.summary = "# Calculation of solar position, rise & set times"
37
+
38
+ if s.respond_to? :specification_version then
39
+ s.specification_version = 3
40
+
41
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
42
+ s.add_development_dependency(%q<shoulda>, [">= 0"])
43
+ s.add_development_dependency(%q<rdoc>, ["~> 3.12"])
44
+ s.add_development_dependency(%q<bundler>, ["~> 1"])
45
+ s.add_development_dependency(%q<jeweler>, ["~> 1.8.4"])
46
+ else
47
+ s.add_dependency(%q<shoulda>, [">= 0"])
48
+ s.add_dependency(%q<rdoc>, ["~> 3.12"])
49
+ s.add_dependency(%q<bundler>, ["~> 1"])
50
+ s.add_dependency(%q<jeweler>, ["~> 1.8.4"])
51
+ end
52
+ else
53
+ s.add_dependency(%q<shoulda>, [">= 0"])
54
+ s.add_dependency(%q<rdoc>, ["~> 3.12"])
55
+ s.add_dependency(%q<bundler>, ["~> 1"])
56
+ s.add_dependency(%q<jeweler>, ["~> 1.8.4"])
57
+ end
58
+ end
59
+
data/test/helper.rb ADDED
@@ -0,0 +1,18 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'test/unit'
11
+ require 'shoulda'
12
+
13
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
14
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
15
+ require 'solar'
16
+
17
+ class Test::Unit::TestCase
18
+ end
@@ -0,0 +1,3 @@
1
+ require 'helper'
2
+
3
+ # TODO: write tests!!
metadata ADDED
@@ -0,0 +1,126 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: solar
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Javier Goizueta
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-10-07 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: shoulda
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rdoc
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: '3.12'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: '3.12'
46
+ - !ruby/object:Gem::Dependency
47
+ name: bundler
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: '1'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '1'
62
+ - !ruby/object:Gem::Dependency
63
+ name: jeweler
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: 1.8.4
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: 1.8.4
78
+ description: ! '# Calculation of solar position, rise & set times for a given position
79
+ & time.'
80
+ email: jgoizueta@gmail.com
81
+ executables: []
82
+ extensions: []
83
+ extra_rdoc_files:
84
+ - LICENSE.txt
85
+ - README.rdoc
86
+ files:
87
+ - .document
88
+ - Gemfile
89
+ - Gemfile.lock
90
+ - LICENSE.txt
91
+ - README.rdoc
92
+ - Rakefile
93
+ - VERSION
94
+ - lib/solar.rb
95
+ - solar.gemspec
96
+ - test/helper.rb
97
+ - test/test_solar.rb
98
+ homepage: http://github.com/jgoizueta/solar
99
+ licenses:
100
+ - MIT
101
+ post_install_message:
102
+ rdoc_options: []
103
+ require_paths:
104
+ - lib
105
+ required_ruby_version: !ruby/object:Gem::Requirement
106
+ none: false
107
+ requirements:
108
+ - - ! '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ segments:
112
+ - 0
113
+ hash: -1434105629411668525
114
+ required_rubygems_version: !ruby/object:Gem::Requirement
115
+ none: false
116
+ requirements:
117
+ - - ! '>='
118
+ - !ruby/object:Gem::Version
119
+ version: '0'
120
+ requirements: []
121
+ rubyforge_project:
122
+ rubygems_version: 1.8.23
123
+ signing_key:
124
+ specification_version: 3
125
+ summary: ! '# Calculation of solar position, rise & set times'
126
+ test_files: []