astronoby 0.3.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +132 -0
  3. data/Gemfile.lock +19 -17
  4. data/README.md +195 -25
  5. data/UPGRADING.md +72 -0
  6. data/lib/astronoby/aberration.rb +7 -5
  7. data/lib/astronoby/angle.rb +26 -34
  8. data/lib/astronoby/astronomical_models/ephemeride_lunaire_parisienne.rb +143 -0
  9. data/lib/astronoby/astronomical_models/moon_phases_periodic_terms.rb +249 -0
  10. data/lib/astronoby/bodies/moon.rb +335 -0
  11. data/lib/astronoby/bodies/sun.rb +129 -132
  12. data/lib/astronoby/constants.rb +31 -0
  13. data/lib/astronoby/coordinates/ecliptic.rb +4 -4
  14. data/lib/astronoby/coordinates/equatorial.rb +7 -5
  15. data/lib/astronoby/coordinates/horizontal.rb +24 -12
  16. data/lib/astronoby/distance.rb +83 -0
  17. data/lib/astronoby/epoch.rb +0 -2
  18. data/lib/astronoby/equinox_solstice.rb +3 -2
  19. data/lib/astronoby/events/moon_phases.rb +143 -0
  20. data/lib/astronoby/events/observation_events.rb +259 -0
  21. data/lib/astronoby/events/rise_transit_set_iteration.rb +215 -0
  22. data/lib/astronoby/events/twilight_events.rb +121 -0
  23. data/lib/astronoby/geocentric_parallax.rb +36 -56
  24. data/lib/astronoby/mean_obliquity.rb +2 -2
  25. data/lib/astronoby/moon_phase.rb +43 -0
  26. data/lib/astronoby/nutation.rb +5 -3
  27. data/lib/astronoby/observer.rb +39 -18
  28. data/lib/astronoby/precession.rb +1 -1
  29. data/lib/astronoby/refraction.rb +8 -10
  30. data/lib/astronoby/time/greenwich_sidereal_time.rb +18 -29
  31. data/lib/astronoby/time/local_sidereal_time.rb +4 -4
  32. data/lib/astronoby/util/maths.rb +72 -0
  33. data/lib/astronoby/util/time.rb +88 -0
  34. data/lib/astronoby/util/trigonometry.rb +4 -4
  35. data/lib/astronoby/version.rb +1 -1
  36. data/lib/astronoby.rb +12 -1
  37. metadata +15 -4
  38. data/lib/astronoby/body.rb +0 -155
@@ -5,17 +5,16 @@ module Astronoby
5
5
  LOW_ALTITUDE_BODY_ANGLE = Angle.from_degrees(15)
6
6
  ZENITH = Angle.from_degrees(90)
7
7
 
8
- def self.angle(coordinates:, observer:)
9
- new(coordinates, observer).refraction_angle
8
+ def self.angle(coordinates:)
9
+ new(coordinates).refraction_angle
10
10
  end
11
11
 
12
- def self.correct_horizontal_coordinates(coordinates:, observer:)
13
- new(coordinates, observer).refract
12
+ def self.correct_horizontal_coordinates(coordinates:)
13
+ new(coordinates).refract
14
14
  end
15
15
 
16
- def initialize(coordinates, observer)
16
+ def initialize(coordinates)
17
17
  @coordinates = coordinates
18
- @observer = observer
19
18
  end
20
19
 
21
20
  # Source:
@@ -27,8 +26,7 @@ module Astronoby
27
26
  Coordinates::Horizontal.new(
28
27
  azimuth: @coordinates.azimuth,
29
28
  altitude: @coordinates.altitude + refraction_angle,
30
- latitude: @coordinates.latitude,
31
- longitude: @coordinates.longitude
29
+ observer: @coordinates.observer
32
30
  )
33
31
  end
34
32
 
@@ -43,11 +41,11 @@ module Astronoby
43
41
  private
44
42
 
45
43
  def pressure
46
- @_pressure ||= @observer.pressure
44
+ @_pressure ||= @coordinates.observer.pressure
47
45
  end
48
46
 
49
47
  def temperature
50
- @_temperature ||= @observer.temperature
48
+ @_temperature ||= @coordinates.observer.temperature
51
49
  end
52
50
 
53
51
  def altitude_in_degrees
@@ -3,11 +3,13 @@
3
3
  module Astronoby
4
4
  class GreenwichSiderealTime
5
5
  JULIAN_CENTURIES_EXPONENTS = [
6
- BigDecimal("6.697374558"),
7
- BigDecimal("2400.051336"),
8
- BigDecimal("0.000025862")
6
+ 6.697374558,
7
+ 2400.051336,
8
+ 0.000025862
9
9
  ].freeze
10
10
 
11
+ SIDEREAL_MINUTE_IN_UT_MINUTE = 0.9972695663
12
+
11
13
  attr_reader :date, :time
12
14
 
13
15
  # Source:
@@ -18,20 +20,20 @@ module Astronoby
18
20
  def self.from_utc(utc)
19
21
  date = utc.to_date
20
22
  julian_day = utc.to_date.ajd
21
- t = (julian_day - Epoch::J2000) / Epoch::DAYS_PER_JULIAN_CENTURY
23
+ t = (julian_day - Epoch::J2000) / Constants::DAYS_PER_JULIAN_CENTURY
22
24
  t0 = (
23
25
  (JULIAN_CENTURIES_EXPONENTS[0] +
24
26
  (JULIAN_CENTURIES_EXPONENTS[1] * t) +
25
- (JULIAN_CENTURIES_EXPONENTS[2] * t * t)) % 24
27
+ (JULIAN_CENTURIES_EXPONENTS[2] * t * t)) % Constants::HOURS_PER_DAY
26
28
  ).abs
27
29
 
28
30
  ut_in_hours = utc.hour +
29
- utc.min / 60.0 +
30
- (utc.sec + utc.subsec) / 3600.0
31
+ utc.min / Constants::MINUTES_PER_HOUR +
32
+ (utc.sec + utc.subsec) / Constants::SECONDS_PER_HOUR
31
33
 
32
- gmst = BigDecimal("1.002737909") * ut_in_hours + t0
33
- gmst += 24 if gmst.negative?
34
- gmst -= 24 if gmst > 24
34
+ gmst = 1.002737909 * ut_in_hours + t0
35
+ gmst += Constants::HOURS_PER_DAY if gmst.negative?
36
+ gmst -= Constants::HOURS_PER_DAY if gmst > Constants::HOURS_PER_DAY
35
37
 
36
38
  new(date: date, time: gmst)
37
39
  end
@@ -49,38 +51,25 @@ module Astronoby
49
51
  def to_utc
50
52
  date = @date
51
53
  julian_day = @date.ajd
52
- t = (julian_day - Epoch::J2000) / Epoch::DAYS_PER_JULIAN_CENTURY
54
+ t = (julian_day - Epoch::J2000) / Constants::DAYS_PER_JULIAN_CENTURY
53
55
 
54
56
  t0 = (
55
57
  (JULIAN_CENTURIES_EXPONENTS[0] +
56
58
  (JULIAN_CENTURIES_EXPONENTS[1] * t) +
57
- (JULIAN_CENTURIES_EXPONENTS[2] * t * t)) % 24
59
+ (JULIAN_CENTURIES_EXPONENTS[2] * t * t)) % Constants::HOURS_PER_DAY
58
60
  ).abs
59
61
 
60
62
  a = @time - t0
61
- a += 24 if a.negative?
62
- a -= 24 if a > 24
63
+ a += Constants::HOURS_PER_DAY if a.negative?
64
+ a -= Constants::HOURS_PER_DAY if a > Constants::HOURS_PER_DAY
63
65
 
64
- utc = BigDecimal("0.9972695663") * a
66
+ utc = SIDEREAL_MINUTE_IN_UT_MINUTE * a
65
67
 
66
- decimal_hour_to_time(date, utc)
68
+ Util::Time.decimal_hour_to_time(date, utc)
67
69
  end
68
70
 
69
71
  def to_lst(longitude:)
70
72
  LocalSiderealTime.from_gst(gst: self, longitude: longitude)
71
73
  end
72
-
73
- private
74
-
75
- def decimal_hour_to_time(date, decimal)
76
- absolute_hour = decimal.abs
77
- hour = absolute_hour.floor
78
- decimal_minute = 60 * (absolute_hour - hour)
79
- absolute_decimal_minute = (60 * (absolute_hour - hour)).abs
80
- minute = decimal_minute.floor
81
- second = 60 * (absolute_decimal_minute - absolute_decimal_minute.floor)
82
-
83
- ::Time.utc(date.year, date.month, date.day, hour, minute, second).round
84
- end
85
74
  end
86
75
  end
@@ -12,8 +12,8 @@ module Astronoby
12
12
  def self.from_gst(gst:, longitude:)
13
13
  date = gst.date
14
14
  time = gst.time + longitude.hours
15
- time += 24 if time.negative?
16
- time -= 24 if time > 24
15
+ time += Constants::HOURS_PER_DAY if time.negative?
16
+ time -= Constants::HOURS_PER_DAY if time > Constants::HOURS_PER_DAY
17
17
 
18
18
  new(date: date, time: time, longitude: longitude)
19
19
  end
@@ -32,8 +32,8 @@ module Astronoby
32
32
  def to_gst
33
33
  date = @date
34
34
  time = @time - @longitude.hours
35
- time += 24 if time.negative?
36
- time -= 24 if time > 24
35
+ time += Constants::HOURS_PER_DAY if time.negative?
36
+ time -= Constants::HOURS_PER_DAY if time > Constants::HOURS_PER_DAY
37
37
 
38
38
  GreenwichSiderealTime.new(date: date, time: time)
39
39
  end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Astronoby
4
+ module Util
5
+ module Maths
6
+ class << self
7
+ # Source:
8
+ # Title: Astronomical Algorithms
9
+ # Author: Jean Meeus
10
+ # Edition: 2nd edition
11
+ # Chapter: 3 - Interpolation
12
+
13
+ # @param values [Array<Numeric>] First term
14
+ # @param factor [Numeric] Interpolation factor
15
+ # @return [Float] Interpolated value
16
+ def interpolate(values, factor)
17
+ unless factor.between?(0, 1)
18
+ raise IncompatibleArgumentsError,
19
+ "Interpolation factor must be between 0 and 1, got #{factor}"
20
+ end
21
+
22
+ if values.length == 3
23
+ return interpolate_3_terms(values, factor)
24
+ elsif values.length == 5
25
+ return interpolate_5_terms(values, factor)
26
+ end
27
+
28
+ raise IncompatibleArgumentsError,
29
+ "Only 3 or 5 terms are supported for interpolation"
30
+ end
31
+
32
+ private
33
+
34
+ # @return [Float] Interpolated value
35
+ def interpolate_3_terms(terms, factor)
36
+ y1, y2, y3 = terms
37
+
38
+ a = y2 - y1
39
+ b = y3 - y2
40
+ c = b - a
41
+
42
+ y2 + (factor / 2.0) * (a + b + factor * c)
43
+ end
44
+
45
+ # @return [Float] Interpolated value
46
+ def interpolate_5_terms(terms, factor)
47
+ y1, y2, y3, y4, y5 = terms
48
+
49
+ a = y2 - y1
50
+ b = y3 - y2
51
+ c = y4 - y3
52
+ d = y5 - y4
53
+
54
+ e = b - a
55
+ f = c - b
56
+ g = d - c
57
+
58
+ h = f - e
59
+ j = g - f
60
+
61
+ k = j - h
62
+
63
+ y3 +
64
+ factor * ((b + c) / 2.0 - (h + j) / 12.0) +
65
+ factor**2 * (f / 2.0 - k / 24.0) +
66
+ factor**3 * (h + j) / 12.0 +
67
+ factor**4 * k / 24.0
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Astronoby
4
+ module Util
5
+ module Time
6
+ # @param date [Date]
7
+ # @param decimal [Numeric] Hour of the day, in decimal hours
8
+ # @return [::Time] Date and time
9
+ def self.decimal_hour_to_time(date, decimal)
10
+ absolute_hour = decimal.abs
11
+ hour = absolute_hour.floor
12
+
13
+ unless hour.between?(0, Constants::HOURS_PER_DAY)
14
+ raise(
15
+ IncompatibleArgumentsError,
16
+ "Hour must be between 0 and #{Constants::HOURS_PER_DAY.to_i}, got #{hour}"
17
+ )
18
+ end
19
+
20
+ decimal_minute = Constants::MINUTES_PER_HOUR * (absolute_hour - hour)
21
+ absolute_decimal_minute = (
22
+ Constants::MINUTES_PER_HOUR * (absolute_hour - hour)
23
+ ).abs
24
+ minute = decimal_minute.floor
25
+ second = Constants::SECONDS_PER_MINUTE *
26
+ (absolute_decimal_minute - absolute_decimal_minute.floor)
27
+
28
+ ::Time.utc(date.year, date.month, date.day, hour, minute, second).round
29
+ end
30
+
31
+ # @param instant [Numeric, Time, Date, DateTime]
32
+ # @return [Integer, Float] Number of leap seconds for the given instant
33
+ def self.terrestrial_universal_time_delta(instant)
34
+ # Source:
35
+ # Title: Astronomical Algorithms
36
+ # Author: Jean Meeus
37
+ # Edition: 2nd edition
38
+ # Chapter: 10 - Dynamical Time and Universal Time
39
+
40
+ jd = case instant
41
+ when Numeric
42
+ instant
43
+ when ::Time, ::Date, ::DateTime
44
+ Epoch.from_time(instant)
45
+ else
46
+ raise IncompatibleArgumentsError,
47
+ "Expected a Numeric, Time, Date or DateTime object, got #{instant.class}"
48
+ end
49
+
50
+ return 69 if jd >= 2457754.5
51
+ return 68 if jd >= 2457204.5
52
+ return 67 if jd >= 2456109.5
53
+ return 66 if jd >= 2454832.5
54
+ return 65 if jd >= 2453736.5
55
+ return 64 if jd >= 2451179.5
56
+ return 63 if jd >= 2450814.5
57
+
58
+ theta = ((jd - Epoch::J1900) / 365.25) / 100.0
59
+ if (2415020.5...2450814.5).cover?(jd) # 1900 - 1997
60
+ return -2.44 +
61
+ 87.24 * theta +
62
+ 815.20 * theta**2 -
63
+ 2_637.80 * theta**3 -
64
+ 18_756.33 * theta**4 +
65
+ 124_906.15 * theta**5 -
66
+ 303_191.19 * theta**6 +
67
+ 372_919.88 * theta**7 -
68
+ 232_424.66 * theta**8 +
69
+ 58_353.42 * theta**9
70
+ elsif (2378496.5...2415020.5).cover?(jd) # 1800 - 1899
71
+ return -2.5 +
72
+ 228.95 * theta +
73
+ 5_218.61 * theta**2 +
74
+ 56_282.84 * theta**3 +
75
+ 324_011.78 * theta**4 +
76
+ 1_061_660.75 * theta**5 +
77
+ 2_087_298.89 * theta**6 +
78
+ 2_513_807.78 * theta**7 +
79
+ 1_818_961.41 * theta**8 +
80
+ 727_058.63 * theta**9 +
81
+ 123_563.95 * theta**10
82
+ end
83
+
84
+ 0.0
85
+ end
86
+ end
87
+ end
88
+ end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "bigdecimal/math"
4
-
5
3
  module Astronoby
6
4
  module Util
7
5
  module Trigonometry
@@ -15,10 +13,12 @@ module Astronoby
15
13
  return angle if y.positive? && x.positive?
16
14
 
17
15
  if y.negative? && x.positive?
18
- return Angle.from_degrees(angle.degrees + 360)
16
+ return Angle.from_degrees(
17
+ angle.degrees + Constants::DEGREES_PER_CIRCLE
18
+ )
19
19
  end
20
20
 
21
- Angle.from_degrees(angle.degrees + 180)
21
+ Angle.from_degrees(angle.degrees + Constants::DEGREES_PER_CIRCLE / 2)
22
22
  end
23
23
  end
24
24
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Astronoby
4
- VERSION = "0.3.0"
4
+ VERSION = "0.5.0"
5
5
  end
data/lib/astronoby.rb CHANGED
@@ -1,10 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "astronoby/constants"
3
4
  require "astronoby/angle"
4
5
  require "astronoby/angles/dms"
5
6
  require "astronoby/angles/hms"
7
+ require "astronoby/distance"
6
8
  require "astronoby/epoch"
7
- require "astronoby/body"
9
+ require "astronoby/astronomical_models/ephemeride_lunaire_parisienne"
10
+ require "astronoby/astronomical_models/moon_phases_periodic_terms"
11
+ require "astronoby/bodies/moon"
8
12
  require "astronoby/bodies/sun"
9
13
  require "astronoby/coordinates/ecliptic"
10
14
  require "astronoby/coordinates/equatorial"
@@ -12,8 +16,13 @@ require "astronoby/coordinates/horizontal"
12
16
  require "astronoby/aberration"
13
17
  require "astronoby/equinox_solstice"
14
18
  require "astronoby/errors"
19
+ require "astronoby/events/moon_phases"
20
+ require "astronoby/events/observation_events"
21
+ require "astronoby/events/rise_transit_set_iteration"
22
+ require "astronoby/events/twilight_events"
15
23
  require "astronoby/geocentric_parallax"
16
24
  require "astronoby/mean_obliquity"
25
+ require "astronoby/moon_phase"
17
26
  require "astronoby/nutation"
18
27
  require "astronoby/observer"
19
28
  require "astronoby/precession"
@@ -21,6 +30,8 @@ require "astronoby/refraction"
21
30
  require "astronoby/time/greenwich_sidereal_time"
22
31
  require "astronoby/time/local_sidereal_time"
23
32
  require "astronoby/util/astrodynamics"
33
+ require "astronoby/util/maths"
34
+ require "astronoby/util/time"
24
35
  require "astronoby/util/trigonometry"
25
36
  require "astronoby/true_obliquity"
26
37
  require "astronoby/version"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: astronoby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rémy Hannequin
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-03-29 00:00:00.000000000 Z
11
+ date: 2024-06-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: matrix
@@ -91,16 +91,25 @@ files:
91
91
  - lib/astronoby/angle.rb
92
92
  - lib/astronoby/angles/dms.rb
93
93
  - lib/astronoby/angles/hms.rb
94
+ - lib/astronoby/astronomical_models/ephemeride_lunaire_parisienne.rb
95
+ - lib/astronoby/astronomical_models/moon_phases_periodic_terms.rb
96
+ - lib/astronoby/bodies/moon.rb
94
97
  - lib/astronoby/bodies/sun.rb
95
- - lib/astronoby/body.rb
98
+ - lib/astronoby/constants.rb
96
99
  - lib/astronoby/coordinates/ecliptic.rb
97
100
  - lib/astronoby/coordinates/equatorial.rb
98
101
  - lib/astronoby/coordinates/horizontal.rb
102
+ - lib/astronoby/distance.rb
99
103
  - lib/astronoby/epoch.rb
100
104
  - lib/astronoby/equinox_solstice.rb
101
105
  - lib/astronoby/errors.rb
106
+ - lib/astronoby/events/moon_phases.rb
107
+ - lib/astronoby/events/observation_events.rb
108
+ - lib/astronoby/events/rise_transit_set_iteration.rb
109
+ - lib/astronoby/events/twilight_events.rb
102
110
  - lib/astronoby/geocentric_parallax.rb
103
111
  - lib/astronoby/mean_obliquity.rb
112
+ - lib/astronoby/moon_phase.rb
104
113
  - lib/astronoby/nutation.rb
105
114
  - lib/astronoby/observer.rb
106
115
  - lib/astronoby/precession.rb
@@ -109,6 +118,8 @@ files:
109
118
  - lib/astronoby/time/local_sidereal_time.rb
110
119
  - lib/astronoby/true_obliquity.rb
111
120
  - lib/astronoby/util/astrodynamics.rb
121
+ - lib/astronoby/util/maths.rb
122
+ - lib/astronoby/util/time.rb
112
123
  - lib/astronoby/util/trigonometry.rb
113
124
  - lib/astronoby/version.rb
114
125
  homepage: https://github.com/rhannequin/astronoby
@@ -126,7 +137,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
126
137
  requirements:
127
138
  - - ">="
128
139
  - !ruby/object:Gem::Version
129
- version: 3.2.0
140
+ version: 3.0.0
130
141
  required_rubygems_version: !ruby/object:Gem::Requirement
131
142
  requirements:
132
143
  - - ">="
@@ -1,155 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Astronoby
4
- class Body
5
- DEFAULT_REFRACTION_VERTICAL_SHIFT = Angle.from_dms(0, 34, 0)
6
- RISING_SETTING_HOUR_ANGLE_RATIO_RANGE = (-1..1)
7
-
8
- def initialize(equatorial_coordinates)
9
- @equatorial_coordinates = equatorial_coordinates
10
- end
11
-
12
- # Source:
13
- # Title: Practical Astronomy with your Calculator or Spreadsheet
14
- # Authors: Peter Duffett-Smith and Jonathan Zwart
15
- # Edition: Cambridge University Press
16
- # Chapter: 33 - Rising and setting
17
-
18
- # @param latitude [Astronoby::Angle] Latitude of the observer
19
- # @param longitude [Astronoby::Angle] Longitude of the observer
20
- # @param date [Date] Date of the event
21
- # @param apparent [Boolean] Compute apparent or true data
22
- # @param vertical_shift [Astronoby::Angle] Vertical shift correction angle
23
- # @return [Time, nil] Sunrise time
24
- def rising_time(
25
- latitude:,
26
- longitude:,
27
- date:,
28
- apparent: true,
29
- vertical_shift: nil
30
- )
31
- time_ratio = time_ratio(latitude, apparent, vertical_shift)
32
- return nil unless RISING_SETTING_HOUR_ANGLE_RATIO_RANGE.cover?(time_ratio)
33
-
34
- hour_angle = Angle.acos(time_ratio)
35
- local_sidereal_time = LocalSiderealTime.new(
36
- date: date,
37
- time: right_ascension.hours - hour_angle.hours,
38
- longitude: longitude
39
- )
40
-
41
- local_sidereal_time.to_gst.to_utc
42
- end
43
-
44
- # Source:
45
- # Title: Practical Astronomy with your Calculator or Spreadsheet
46
- # Authors: Peter Duffett-Smith and Jonathan Zwart
47
- # Edition: Cambridge University Press
48
- # Chapter: 33 - Rising and setting
49
-
50
- # @param latitude [Astronoby::Angle] Latitude of the observer
51
- # @param apparent [Boolean] Compute apparent or true data
52
- # @param vertical_shift [Astronoby::Angle] Vertical shift correction angle
53
- # @return [Astronoby::Angle, nil] Sunrise azimuth
54
- def rising_azimuth(latitude:, apparent: true, vertical_shift: nil)
55
- time_ratio = time_ratio(latitude, apparent, vertical_shift)
56
- return nil unless RISING_SETTING_HOUR_ANGLE_RATIO_RANGE.cover?(time_ratio)
57
-
58
- azimuth_ratio = azimuth_ratio(latitude, apparent, vertical_shift)
59
-
60
- Angle.acos(azimuth_ratio)
61
- end
62
-
63
- # Source:
64
- # Title: Practical Astronomy with your Calculator or Spreadsheet
65
- # Authors: Peter Duffett-Smith and Jonathan Zwart
66
- # Edition: Cambridge University Press
67
- # Chapter: 33 - Rising and setting
68
-
69
- # @param latitude [Astronoby::Angle] Latitude of the observer
70
- # @param longitude [Astronoby::Angle] Longitude of the observer
71
- # @param date [Date] Date of the event
72
- # @param apparent [Boolean] Compute apparent or true data
73
- # @param vertical_shift [Astronoby::Angle] Vertical shift correction angle
74
- # @return [Time, nil] Sunset time
75
- def setting_time(
76
- latitude:,
77
- longitude:,
78
- date:,
79
- apparent: true,
80
- vertical_shift: nil
81
- )
82
- time_ratio = time_ratio(latitude, apparent, vertical_shift)
83
- return unless RISING_SETTING_HOUR_ANGLE_RATIO_RANGE.cover?(time_ratio)
84
-
85
- hour_angle = Angle.acos(time_ratio)
86
- local_sidereal_time = LocalSiderealTime.new(
87
- date: date,
88
- time: right_ascension.hours + hour_angle.hours,
89
- longitude: longitude
90
- )
91
-
92
- local_sidereal_time.to_gst.to_utc
93
- end
94
-
95
- # Source:
96
- # Title: Practical Astronomy with your Calculator or Spreadsheet
97
- # Authors: Peter Duffett-Smith and Jonathan Zwart
98
- # Edition: Cambridge University Press
99
- # Chapter: 33 - Rising and setting
100
-
101
- # @param latitude [Astronoby::Angle] Latitude of the observer
102
- # @param apparent [Boolean] Compute apparent or true data
103
- # @param vertical_shift [Astronoby::Angle] Vertical shift correction angle
104
- # @return [Astronoby::Angle, nil] Sunset azimuth
105
- def setting_azimuth(latitude:, apparent: true, vertical_shift: nil)
106
- time_ratio = time_ratio(latitude, apparent, vertical_shift)
107
- return nil unless RISING_SETTING_HOUR_ANGLE_RATIO_RANGE.cover?(time_ratio)
108
-
109
- azimuth_ratio = azimuth_ratio(latitude, apparent, vertical_shift)
110
-
111
- Angle.from_degrees(360 - Angle.acos(azimuth_ratio).degrees)
112
- end
113
-
114
- private
115
-
116
- def time_ratio(latitude, apparent, vertical_shift)
117
- shift = if vertical_shift
118
- vertical_shift
119
- elsif apparent
120
- DEFAULT_REFRACTION_VERTICAL_SHIFT
121
- else
122
- Angle.zero
123
- end
124
-
125
- term1 = shift.sin + latitude.sin * declination.sin
126
- term2 = latitude.cos * declination.cos
127
-
128
- -term1 / term2
129
- end
130
-
131
- def azimuth_ratio(latitude, apparent, vertical_shift)
132
- shift = if vertical_shift
133
- vertical_shift
134
- elsif apparent
135
- DEFAULT_REFRACTION_VERTICAL_SHIFT
136
- else
137
- Angle.zero
138
- end
139
-
140
- (declination.sin + shift.sin * latitude.cos) / (shift.cos * latitude.cos)
141
- end
142
-
143
- def azimuth_component(latitude)
144
- declination.sin / latitude.cos
145
- end
146
-
147
- def right_ascension
148
- @equatorial_coordinates.right_ascension
149
- end
150
-
151
- def declination
152
- @equatorial_coordinates.declination
153
- end
154
- end
155
- end