astronoby 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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"
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.4.0"
5
5
  end
data/lib/astronoby.rb CHANGED
@@ -1,10 +1,10 @@
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"
6
7
  require "astronoby/epoch"
7
- require "astronoby/body"
8
8
  require "astronoby/bodies/sun"
9
9
  require "astronoby/coordinates/ecliptic"
10
10
  require "astronoby/coordinates/equatorial"
@@ -12,6 +12,8 @@ require "astronoby/coordinates/horizontal"
12
12
  require "astronoby/aberration"
13
13
  require "astronoby/equinox_solstice"
14
14
  require "astronoby/errors"
15
+ require "astronoby/events/observation_events"
16
+ require "astronoby/events/twilight_events"
15
17
  require "astronoby/geocentric_parallax"
16
18
  require "astronoby/mean_obliquity"
17
19
  require "astronoby/nutation"
@@ -21,6 +23,8 @@ require "astronoby/refraction"
21
23
  require "astronoby/time/greenwich_sidereal_time"
22
24
  require "astronoby/time/local_sidereal_time"
23
25
  require "astronoby/util/astrodynamics"
26
+ require "astronoby/util/maths"
27
+ require "astronoby/util/time"
24
28
  require "astronoby/util/trigonometry"
25
29
  require "astronoby/true_obliquity"
26
30
  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.4.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-04-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: matrix
@@ -92,13 +92,15 @@ files:
92
92
  - lib/astronoby/angles/dms.rb
93
93
  - lib/astronoby/angles/hms.rb
94
94
  - lib/astronoby/bodies/sun.rb
95
- - lib/astronoby/body.rb
95
+ - lib/astronoby/constants.rb
96
96
  - lib/astronoby/coordinates/ecliptic.rb
97
97
  - lib/astronoby/coordinates/equatorial.rb
98
98
  - lib/astronoby/coordinates/horizontal.rb
99
99
  - lib/astronoby/epoch.rb
100
100
  - lib/astronoby/equinox_solstice.rb
101
101
  - lib/astronoby/errors.rb
102
+ - lib/astronoby/events/observation_events.rb
103
+ - lib/astronoby/events/twilight_events.rb
102
104
  - lib/astronoby/geocentric_parallax.rb
103
105
  - lib/astronoby/mean_obliquity.rb
104
106
  - lib/astronoby/nutation.rb
@@ -109,6 +111,8 @@ files:
109
111
  - lib/astronoby/time/local_sidereal_time.rb
110
112
  - lib/astronoby/true_obliquity.rb
111
113
  - lib/astronoby/util/astrodynamics.rb
114
+ - lib/astronoby/util/maths.rb
115
+ - lib/astronoby/util/time.rb
112
116
  - lib/astronoby/util/trigonometry.rb
113
117
  - lib/astronoby/version.rb
114
118
  homepage: https://github.com/rhannequin/astronoby
@@ -126,7 +130,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
126
130
  requirements:
127
131
  - - ">="
128
132
  - !ruby/object:Gem::Version
129
- version: 3.2.0
133
+ version: 3.0.0
130
134
  required_rubygems_version: !ruby/object:Gem::Requirement
131
135
  requirements:
132
136
  - - ">="
@@ -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