class SunCalc
SunCalc
provides methods for calculating sun/moon positions and phases.
Most of the formulas are based on:
Constants
- DEFAULT_SUN_TIMES
Sun times configuration (angle, morning name, evening name).
- J0
- J1970
- J2000
- OBLIQUITY_OF_THE_EARTH
- ONE_DAY_IN_SECONDS
- ONE_RADIAN
- VERSION
Public Class Methods
add_sun_time(angle, rise_name, set_name)
click to toggle source
Adds a custom time to the times configuration.
# File lib/sun_calc.rb, line 67 def self.add_sun_time(angle, rise_name, set_name) @__sun_times__.push([angle, rise_name, set_name]) end
moon_illumination(date = Time.now)
click to toggle source
Calculates illumination parameters for the moon for a given date.
Formulas are based on:
-
Chapter 48 of “Astronomical Algorithms” 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998.
# File lib/sun_calc.rb, line 158 def self.moon_illumination(date = Time.now) d = to_days(date) s = sun_coords(d) m = moon_coords(d) sdist = 149_598_000 # Distance from Earth to Sun in kilometers phi = Math.acos(Math.sin(s[:dec]) * Math.sin(m[:dec]) + Math.cos(s[:dec]) * Math.cos(m[:dec]) * Math.cos(s[:ra] - m[:ra])) inc = Math.atan2(sdist * Math.sin(phi), m[:dist] - sdist * Math.cos(phi)) angle = Math.atan2(Math.cos(s[:dec]) * Math.sin(s[:ra] - m[:ra]), Math.sin(s[:dec]) * Math.cos(m[:dec]) - Math.cos(s[:dec]) * Math.sin(m[:dec]) * Math.cos(s[:ra] - m[:ra])) { fraction: (1 + Math.cos(inc)) / 2, phase: 0.5 + 0.5 * inc * (angle < 0 ? -1 : 1) / Math::PI, angle: angle } end
moon_position(date, lat, lng)
click to toggle source
Calculates moon position for a gived date, latitude, and longitude.
# File lib/sun_calc.rb, line 72 def self.moon_position(date, lat, lng) lw = ONE_RADIAN * -lng phi = ONE_RADIAN * lat d = to_days(date) c = moon_coords(d) h_ = sidereal_time(d, lw) - c[:ra] h = altitude(h_, phi, c[:dec]) # Formula 14.1 from "Astronomical Algorithms" 2nd edition by Jean Meeus # (Willmann-Bell, Richmond) 1998. pa = Math.atan2(Math.sin(h_), Math.tan(phi) * Math.cos(c[:dec]) - Math.sin(c[:dec]) * Math.cos(h_)) h += astro_refraction(h) # altitude correction for refraction { azimuth: azimuth(h_, phi, c[:dec]), altitude: h, distance: c[:dist], parallacticAngle: pa } end
moon_times(date, lat, lng)
click to toggle source
Calculates moon times for a given date, latitude, and longitude.
Calculations for moon rise and set times are based on:
# File lib/sun_calc.rb, line 96 def self.moon_times(date, lat, lng) t = Time.utc(date.year, date.month, date.day) hc = 0.133 * ONE_RADIAN h0 = SunCalc.moon_position(t, lat, lng)[:altitude] - hc ye = 0 max = nil min = nil rise = nil set = nil # Iterate in 2-hour steps checking if a 3-point quadratic curve crosses zero # (which means rise or set). Assumes x values -1, 0, +1. (1...24).step(2).each do |i| h1 = SunCalc.moon_position(hours_later(t, i), lat, lng)[:altitude] - hc h2 = SunCalc.moon_position( hours_later(t, i + 1), lat, lng )[:altitude] - hc a = (h0 + h2) / 2 - h1 b = (h2 - h0) / 2 xe = -b / (2 * a) ye = (a * xe + b) * xe + h1 d = b * b - 4 * a * h1 roots = 0 x1 = 0 x2 = 0 min = i + xe if xe.abs <= 1 && ye < 0 max = i + xe if xe.abs <= 1 && ye > 0 if d >= 0 dx = Math.sqrt(d) / (a.abs * 2) x1 = xe - dx x2 = xe + dx roots += 1 if x1.abs <= 1 roots += 1 if x2.abs <= 1 x1 = x2 if x1 < -1 end if roots == 1 if h0 < 0 rise = i + x1 else set = i + x1 end elsif roots == 2 rise = i + (ye < 0 ? x2 : x1) set = i + (ye < 0 ? x1 : x2) end break if rise && set && min && max h0 = h2 end {}.tap do |result| result[:nadir] = hours_later(t, min) if min result[:lunar_noon] = hours_later(t, max) if max result[:moonrise] = hours_later(t, rise) if rise result[:moonset] = hours_later(t, set) if set result[ye > 0 ? :always_up : :always_down] = true if !rise && !set end end
sun_position(date, lat, lng)
click to toggle source
Calculates sun position for a given date, latitude, and longitude.
# File lib/sun_calc.rb, line 29 def self.sun_position(date, lat, lng) lw = ONE_RADIAN * -lng phi = ONE_RADIAN * lat d = to_days(date) c = sun_coords(d) h = sidereal_time(d, lw) - c[:ra] { azimuth: azimuth(h, phi, c[:dec]), altitude: altitude(h, phi, c[:dec]) } end
sun_times(date, lat, lng)
click to toggle source
Calculates sun times for a given date, latitude, and longitude.
# File lib/sun_calc.rb, line 40 def self.sun_times(date, lat, lng) lw = ONE_RADIAN * -lng phi = ONE_RADIAN * lat d = to_days(date) n = julian_cycle(d, lw) ds = approx_transit(0, lw, n) m = solar_mean_anomaly(ds) l = ecliptic_longitude(m) dec = declination(l, 0) j_noon = solar_transit_j(ds, m, l) { solar_noon: from_julian(j_noon), nadir: from_julian(j_noon - 0.5) }.tap do |result| @__sun_times__.each do |time| begin j_set = get_set_j(time[0] * ONE_RADIAN, lw, phi, dec, n, m, l) j_rise = j_noon - (j_set - j_noon) result[time[1].to_sym] = from_julian(j_rise) result[time[2].to_sym] = from_julian(j_set) rescue Math::DomainError result[time[1].to_sym] = nil result[time[2].to_sym] = nil end end end end