Skip to content

Commit

Permalink
Arithmetic methods support for Angle (#16)
Browse files Browse the repository at this point in the history
This introduces several arithmetic functions in `Angle` to increase readability and developer experience.

### Instance methods

- `Angle#+`: adds two angles' values and returns an angle
- `Angle#-`: subtracts two angles' values and returns an angle
- `Angle#sin`: returns the numeric value (ratio) of the sine of the angle
- `Angle#cos`: returns the numeric value (ratio) of the cosine of the angle
- `Angle#tan`: returns the numeric value (ratio) of the tangent of the angle

###Class methods

- `Angle::asin`: returns a new angle from the radians of a inverse sine ratio
- `Angle::acos`: returns a new angle from the radians of a inverse cosine ratio
- `Angle::atan`: returns a new angle from the radians of a inverse tangent ratio

### Examples

```rb
angle_1 = Astronoby::Angle.as_radians(described_class::PI)
angle_2 = Astronoby::Angle.as_degrees(45)
new_angle = angle_1 + angle_2
new_angle.degrees
# => 225

Astronoby::Angle.as_radians(Math::PI / 6).sin
# => ~ 0.5

angle = Astronoby::Angle.atan(1)
angle.radians
# => ~ π÷4
```
  • Loading branch information
rhannequin authored Feb 23, 2024
1 parent 30edbd0 commit ecd3d2d
Show file tree
Hide file tree
Showing 12 changed files with 209 additions and 111 deletions.
19 changes: 7 additions & 12 deletions lib/astronoby/aberration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,25 +20,20 @@ def initialize(coordinates, sun_longitude)
# Chapter: 36 - Aberration
def apply
delta_longitude = Astronoby::Angle.as_degrees(
-20.5 *
Math.cos(
@sun_longitude.radians - @coordinates.longitude.radians
) / Math.cos(@coordinates.latitude.radians) / 3600
-20.5 * (
@sun_longitude - @coordinates.longitude
).cos / @coordinates.latitude.cos / 3600
)

delta_latitude = Astronoby::Angle.as_degrees(
-20.5 *
Math.sin(@sun_longitude.radians - @coordinates.longitude.radians) *
Math.sin(@coordinates.latitude.radians) / 3600
(@sun_longitude - @coordinates.longitude).sin *
@coordinates.latitude.sin / 3600
)

Astronoby::Coordinates::Ecliptic.new(
latitude: Astronoby::Angle.as_degrees(
@coordinates.latitude.degrees + delta_latitude.degrees
),
longitude: Astronoby::Angle.as_degrees(
@coordinates.longitude.degrees + delta_longitude.degrees
)
latitude: @coordinates.latitude + delta_latitude,
longitude: @coordinates.longitude + delta_longitude
)
end
end
Expand Down
53 changes: 43 additions & 10 deletions lib/astronoby/angle.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,26 +45,59 @@ def as_dms(degree, minute, second)
degrees = degree.abs + minute / MINUTES_PER_HOUR + second / SECONDS_PER_HOUR
as_degrees(sign * degrees)
end

def asin(ratio)
radians = Math.asin(ratio)
as_radians(radians)
end

def acos(ratio)
radians = Math.acos(ratio)
as_radians(radians)
end

def atan(ratio)
radians = Math.atan(ratio)
as_radians(radians)
end
end

def radians
@angle
attr_reader :radians

def initialize(radians)
@radians = if radians.is_a?(Integer) || radians.is_a?(BigDecimal)
BigDecimal(radians)
else
BigDecimal(radians, PRECISION)
end
end

def degrees
@angle * PI_IN_DEGREES / PI
@radians * PI_IN_DEGREES / PI
end

def hours
@angle / RADIAN_PER_HOUR
@radians / RADIAN_PER_HOUR
end

def initialize(angle)
@angle = if angle.is_a?(Integer) || angle.is_a?(BigDecimal)
BigDecimal(angle)
else
BigDecimal(angle, PRECISION)
end
def +(other)
self.class.as_radians(radians + other.radians)
end

def -(other)
self.class.as_radians(@radians - other.radians)
end

def sin
Math.sin(radians)
end

def cos
Math.cos(radians)
end

def tan
Math.tan(radians)
end

def str(format)
Expand Down
6 changes: 3 additions & 3 deletions lib/astronoby/bodies/sun.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ def ecliptic_coordinates
Coordinates::Ecliptic.new(
latitude: Angle.zero,
longitude: Angle.as_degrees(
(true_anomaly.degrees + longitude_at_perigee.degrees) % 360
(true_anomaly + longitude_at_perigee).degrees % 360
)
)
end
Expand All @@ -33,7 +33,7 @@ def horizontal_coordinates(latitude:, longitude:)

def mean_anomaly
Angle.as_degrees(
(longitude_at_base_epoch.degrees - longitude_at_perigee.degrees) % 360
(longitude_at_base_epoch - longitude_at_perigee).degrees % 360
)
end

Expand All @@ -50,7 +50,7 @@ def true_anomaly
) * Math.tan(eccentric_anomaly.radians / 2)

Astronoby::Angle.as_degrees(
(Astronoby::Angle.as_radians(Math.atan(tan)).degrees * 2) % 360
(Astronoby::Angle.atan(tan).degrees * 2) % 360
)
end

Expand Down
9 changes: 3 additions & 6 deletions lib/astronoby/body.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def rising_azimuth(latitude:)
ar = azimuth_component(latitude: latitude)
return nil if ar >= 1

Astronoby::Angle.as_radians(Math.acos(ar))
Astronoby::Angle.acos(ar)
end

# Source:
Expand Down Expand Up @@ -72,17 +72,14 @@ def setting_azimuth(latitude:)
private

def azimuth_component(latitude:)
Math.sin(@equatorial_coordinates.declination.radians)./(
Math.cos(latitude.radians)
)
@equatorial_coordinates.declination.sin / latitude.cos
end

def h2(latitude:)
ar = azimuth_component(latitude: latitude)
return nil if ar >= 1

h1 = Math.tan(latitude.radians) *
Math.tan(@equatorial_coordinates.declination.radians)
h1 = latitude.tan * @equatorial_coordinates.declination.tan
return nil if h1.abs > 1

Astronoby::Angle.as_radians(Math.acos(-h1) / 15.0)
Expand Down
24 changes: 9 additions & 15 deletions lib/astronoby/coordinates/ecliptic.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,25 +17,19 @@ def initialize(latitude:, longitude:)
# Chapter: 4 - Orbits and Coordinate Systems
def to_equatorial(epoch:)
mean_obliquity = Astronoby::MeanObliquity.for_epoch(epoch)
obliquity_in_radians = mean_obliquity.value.radians
longitude_in_radians = @longitude.radians
latitude_in_radians = @latitude.radians
obliquity = mean_obliquity.value

y = Astronoby::Angle.as_radians(
Math.sin(longitude_in_radians) * Math.cos(obliquity_in_radians) -
Math.tan(latitude_in_radians) * Math.sin(obliquity_in_radians)
)
x = Astronoby::Angle.as_radians(Math.cos(longitude_in_radians))
r = Astronoby::Angle.as_radians(Math.atan(y.radians / x.radians))
right_ascension = Astronoby::Angle.as_radians(
Astronoby::Util::Trigonometry.adjustement_for_arctangent(y, x, r).radians
@longitude.sin * obliquity.cos - @latitude.tan * obliquity.sin
)
x = Astronoby::Angle.as_radians(@longitude.cos)
r = Astronoby::Angle.atan(y.radians / x.radians)
right_ascension = Astronoby::Util::Trigonometry
.adjustement_for_arctangent(y, x, r)

declination = Astronoby::Angle.as_radians(
Math.asin(
Math.sin(latitude_in_radians) * Math.cos(obliquity_in_radians) +
Math.cos(latitude_in_radians) * Math.sin(obliquity_in_radians) * Math.sin(longitude_in_radians)
)
declination = Astronoby::Angle.asin(
@latitude.sin * obliquity.cos +
@latitude.cos * obliquity.sin * @longitude.sin
)

Equatorial.new(
Expand Down
39 changes: 15 additions & 24 deletions lib/astronoby/coordinates/equatorial.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,15 @@ def compute_hour_angle(time:, longitude:)

def to_horizontal(time:, latitude:, longitude:)
ha = @hour_angle || compute_hour_angle(time: time, longitude: longitude)
t0 = @declination.sin * latitude.sin +
@declination.cos * latitude.cos * ha.cos
altitude = Astronoby::Angle.asin(t0)

latitude_radians = latitude.radians
declination_radians = @declination.radians
t1 = @declination.sin - latitude.sin * altitude.sin
t2 = t1 / (latitude.cos * altitude.cos)
azimuth = Astronoby::Angle.acos(t2)

t0 = Math.sin(declination_radians) * Math.sin(latitude_radians) +
Math.cos(declination_radians) * Math.cos(latitude_radians) * Math.cos(ha.radians)
altitude = Astronoby::Angle.as_radians(Math.asin(t0))

t1 = Math.sin(declination_radians) -
Math.sin(latitude_radians) * Math.sin(altitude.radians)
t2 = t1 / (Math.cos(latitude_radians) * Math.cos(altitude.radians))
sin_hour_angle = Math.sin(ha.radians)
azimuth = Astronoby::Angle.as_radians(Math.acos(t2))
if sin_hour_angle.positive?
if ha.sin.positive?
azimuth = Astronoby::Angle.as_degrees(BigDecimal("360") - azimuth.degrees)
end

Expand All @@ -63,23 +58,19 @@ def to_horizontal(time:, latitude:, longitude:)
# Chapter: 4 - Orbits and Coordinate Systems
def to_ecliptic(epoch:)
mean_obliquity = Astronoby::MeanObliquity.for_epoch(epoch)
obliquity_in_radians = mean_obliquity.value.radians
right_ascension_in_radians = @right_ascension.radians
declination_in_radians = @declination.radians
obliquity = mean_obliquity.value

y = Astronoby::Angle.as_radians(
Math.sin(right_ascension_in_radians) * Math.cos(obliquity_in_radians) +
Math.tan(declination_in_radians) * Math.sin(obliquity_in_radians)
@right_ascension.sin * obliquity.cos +
@declination.tan * obliquity.sin
)
x = Astronoby::Angle.as_radians(Math.cos(right_ascension_in_radians))
r = Astronoby::Angle.as_radians(Math.atan(y.radians / x.radians))
x = Astronoby::Angle.as_radians(@right_ascension.cos)
r = Astronoby::Angle.atan(y.radians / x.radians)
longitude = Astronoby::Util::Trigonometry.adjustement_for_arctangent(y, x, r)

latitude = Astronoby::Angle.as_radians(
Math.asin(
Math.sin(declination_in_radians) * Math.cos(obliquity_in_radians) -
Math.cos(declination_in_radians) * Math.sin(obliquity_in_radians) * Math.sin(right_ascension_in_radians)
)
latitude = Astronoby::Angle.asin(
@declination.sin * obliquity.cos -
@declination.cos * obliquity.sin * @right_ascension.sin
)

Ecliptic.new(
Expand Down
20 changes: 8 additions & 12 deletions lib/astronoby/coordinates/horizontal.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,19 @@ def initialize(
end

def to_equatorial(time:)
latitude_radians = @latitude.radians
t0 = @altitude.sin * @latitude.sin +
@altitude.cos * @latitude.cos * @azimuth.cos

t0 = Math.sin(@altitude.radians) * Math.sin(latitude_radians) +
Math.cos(@altitude.radians) * Math.cos(latitude_radians) * Math.cos(@azimuth.radians)
declination = Astronoby::Angle.asin(t0)

declination = Astronoby::Angle.as_radians(Math.asin(t0))
t1 = @altitude.sin -
@latitude.sin * declination.sin

t1 = Math.sin(@altitude.radians) -
Math.sin(latitude_radians) * Math.sin(declination.radians)

hour_angle_degrees = Astronoby::Angle.as_radians(
Math.acos(
t1 / (Math.cos(latitude_radians) * Math.cos(declination.radians))
)
hour_angle_degrees = Astronoby::Angle.acos(
t1 / (@latitude.cos * declination.cos)
).degrees

if Math.sin(@azimuth.radians).positive?
if @azimuth.sin.positive?
hour_angle_degrees = Astronoby::Angle.as_degrees(
BigDecimal("360") - hour_angle_degrees
).degrees
Expand Down
4 changes: 2 additions & 2 deletions lib/astronoby/nutation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def for_ecliptic_longitude
0,
0,
(
-17.2 * Math.sin(moon_ascending_node_longitude.radians) -
-17.2 * moon_ascending_node_longitude.sin -
1.3 * Math.sin(2 * sun_mean_longitude.radians)
)
)
Expand All @@ -36,7 +36,7 @@ def for_obliquity_of_the_ecliptic
0,
0,
(
9.2 * Math.cos(moon_ascending_node_longitude.radians) +
9.2 * moon_ascending_node_longitude.cos +
0.5 * Math.cos(2 * sun_mean_longitude.radians)
)
)
Expand Down
34 changes: 16 additions & 18 deletions lib/astronoby/precession.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,13 @@ def initialize(coordinates, epoch)
# Edition: Cambridge University Press
# Chapter: 34 - Precession
def precess
right_ascension = @coordinates.right_ascension.radians
declination = @coordinates.declination.radians
matrix_a = matrix_for_epoch(@coordinates.epoch)
matrix_b = matrix_for_epoch(@epoch).transpose

vector = Vector[
Math.cos(right_ascension) * Math.cos(declination),
Math.sin(right_ascension) * Math.cos(declination),
Math.sin(declination)
@coordinates.right_ascension.cos * @coordinates.declination.cos,
@coordinates.right_ascension.sin * @coordinates.declination.cos,
@coordinates.declination.sin
]

s = matrix_a * vector
Expand All @@ -37,9 +35,9 @@ def precess
right_ascension: Astronoby::Util::Trigonometry.adjustement_for_arctangent(
Astronoby::Angle.as_radians(w[1]),
Astronoby::Angle.as_radians(w[0]),
Astronoby::Angle.as_radians(Math.atan(w[1] / w[0]))
Astronoby::Angle.atan(w[1] / w[0])
),
declination: Astronoby::Angle.as_radians(Math.asin(w[2])),
declination: Astronoby::Angle.asin(w[2]),
epoch: @epoch
)
end
Expand All @@ -51,22 +49,22 @@ def matrix_for_epoch(epoch)
Astronoby::Epoch::DAYS_PER_JULIAN_CENTURY
)

ζ = Astronoby::Angle.as_degrees(
zeta = Astronoby::Angle.as_degrees(
0.6406161 * t + 0.0000839 * t * t + 0.000005 * t * t * t
).radians
)
z = Astronoby::Angle.as_degrees(
0.6406161 * t + 0.0003041 * t * t + 0.0000051 * t * t * t
).radians
θ = Astronoby::Angle.as_degrees(
)
theta = Astronoby::Angle.as_degrees(
0.5567530 * t - 0.0001185 * t * t - 0.0000116 * t * t * t
).radians
)

cx = Math.cos(ζ)
sx = Math.sin(ζ)
cz = Math.cos(z)
sz = Math.sin(z)
ct = Math.cos(θ)
st = Math.sin(θ)
cx = zeta.cos
sx = zeta.sin
cz = z.cos
sz = z.sin
ct = theta.cos
st = theta.sin

Matrix[
[
Expand Down
6 changes: 2 additions & 4 deletions lib/astronoby/refraction.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def refract
zenith_angle = Astronoby::Angle.as_degrees(
90 - @coordinates.altitude.degrees
)
0.00452 * @pressure * Math.tan(zenith_angle.radians) / (273 + @temperature)
0.00452 * @pressure * zenith_angle.tan / (273 + @temperature)
else
(
@pressure *
Expand All @@ -54,9 +54,7 @@ def refract

Astronoby::Coordinates::Horizontal.new(
azimuth: @coordinates.azimuth,
altitude: Astronoby::Angle.as_degrees(
@coordinates.altitude.degrees + refraction_angle.degrees
),
altitude: @coordinates.altitude + refraction_angle,
latitude: @coordinates.latitude,
longitude: @coordinates.longitude
)
Expand Down
Loading

0 comments on commit ecd3d2d

Please sign in to comment.