Class: Astronoby::Coordinates::Geodetic

Inherits:
Object
  • Object
show all
Defined in:
lib/astronoby/coordinates/geodetic.rb

Overview

Geodetic coordinate system (WGS-84 latitude, longitude, and elevation).

Geodetic coordinates describe a position on or above the Earth’s surface using the WGS-84 reference ellipsoid, the same system used by GPS.

The reverse conversion from ECEF (Earth-Centered Earth-Fixed) Cartesian coordinates uses Bowring’s iterative method, which converges in 2-3 iterations for typical satellite altitudes.

Constant Summary collapse

SEMI_MINOR_AXIS =
Constants::WGS84_EARTH_EQUATORIAL_RADIUS_IN_METERS *
(1 - Constants::WGS84_FLATTENING)
SECOND_ECCENTRICITY_SQUARED =
(Constants::WGS84_EARTH_EQUATORIAL_RADIUS_IN_METERS**2 -
  SEMI_MINOR_AXIS**2) /
SEMI_MINOR_AXIS**2
MAX_ITERATIONS =
10
CONVERGENCE_THRESHOLD =
1e-12

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(latitude:, longitude:, elevation:) ⇒ Geodetic

Returns a new instance of Geodetic.

Parameters:



37
38
39
40
41
# File 'lib/astronoby/coordinates/geodetic.rb', line 37

def initialize(latitude:, longitude:, elevation:)
  @latitude = latitude
  @longitude = longitude
  @elevation = elevation
end

Instance Attribute Details

#elevationAstronoby::Distance (readonly)

Returns elevation above the WGS-84 ellipsoid.

Returns:



31
32
33
# File 'lib/astronoby/coordinates/geodetic.rb', line 31

def elevation
  @elevation
end

#latitudeAstronoby::Angle (readonly)

Returns geodetic latitude.

Returns:



25
26
27
# File 'lib/astronoby/coordinates/geodetic.rb', line 25

def latitude
  @latitude
end

#longitudeAstronoby::Angle (readonly)

Returns geodetic longitude.

Returns:



28
29
30
# File 'lib/astronoby/coordinates/geodetic.rb', line 28

def longitude
  @longitude
end

Class Method Details

.from_ecef(position) ⇒ Astronoby::Coordinates::Geodetic

Converts ECEF Cartesian coordinates to geodetic coordinates using Bowring’s iterative method.

Source:

Title: Transformation from Spatial to Geographical Coordinates
Author: B. R. Bowring
Edition: Survey Review, Vol. 23, No. 181, 1976

Parameters:

Returns:



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/astronoby/coordinates/geodetic.rb', line 53

def self.from_ecef(position)
  x = position.x.m
  y = position.y.m
  z = position.z.m

  a = Constants::WGS84_EARTH_EQUATORIAL_RADIUS_IN_METERS
  e2 = Constants::WGS84_ECCENTICITY_SQUARED

  p = Math.sqrt(x * x + y * y)
  longitude = Math.atan2(y, x)

  theta = Math.atan2(z * a, p * SEMI_MINOR_AXIS)
  latitude = Math.atan2(
    z + SECOND_ECCENTRICITY_SQUARED * SEMI_MINOR_AXIS *
      Math.sin(theta)**3,
    p - e2 * a * Math.cos(theta)**3
  )

  MAX_ITERATIONS.times do
    prev_latitude = latitude
    theta = Math.atan2(
      (1 - Constants::WGS84_FLATTENING) * Math.sin(latitude),
      Math.cos(latitude)
    )
    latitude = Math.atan2(
      z + SECOND_ECCENTRICITY_SQUARED * SEMI_MINOR_AXIS *
        Math.sin(theta)**3,
      p - e2 * a * Math.cos(theta)**3
    )
    break if (latitude - prev_latitude).abs < CONVERGENCE_THRESHOLD
  end

  sin_lat = Math.sin(latitude)
  n = a / Math.sqrt(1 - e2 * sin_lat * sin_lat)

  elevation = if Math.cos(latitude).abs > 1e-10
    p / Math.cos(latitude) - n
  else
    z / sin_lat - n * (1 - e2)
  end

  new(
    latitude: Angle.from_radians(latitude),
    longitude: Angle.from_radians(longitude),
    elevation: Distance.from_meters(elevation)
  )
end