Class: Geospatial::Location

Inherits:
Object
  • Object
show all
Defined in:
lib/geospatial/location.rb

Overview

This location is specifically relating to a WGS84 coordinate on Earth.

Constant Summary collapse

WGS84_A =

WGS 84 semi-major axis constant in meters

6378137.0
WGS84_B =

WGS 84 semi-minor axis constant in meters

6356752.3
EARTH_RADIUS =
(WGS84_A + WGS84_B) / 2.0
WGS84_E =

WGS 84 eccentricity

8.1819190842622e-2
R2D =

Radians to degrees multiplier

(180.0 / Math::PI)
D2R =
(Math::PI / 180.0)
MIN_LONGITUDE =
-180 * D2R
MAX_LONGITUDE =
180 * D2R
VALID_LONGITUDE =
MIN_LONGITUDE...MAX_LONGITUDE
MIN_LATITUDE =
-90.0 * D2R
MAX_LATITUDE =
90 * D2R
VALID_LATITUDE =
MIN_LATITUDE...MAX_LATITUDE

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(longitude, latitude) ⇒ Location

Returns a new instance of Location.



76
77
78
79
# File 'lib/geospatial/location.rb', line 76

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

Instance Attribute Details

#latitudeObject (readonly)

-90 -> 90 (equivalent to y)



96
97
98
# File 'lib/geospatial/location.rb', line 96

def latitude
  @latitude
end

#longitudeObject (readonly)

-180 -> 180 (equivalent to x)



95
96
97
# File 'lib/geospatial/location.rb', line 95

def longitude
  @longitude
end

Class Method Details

.from_ecef(x, y, z) ⇒ Object



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/geospatial/location.rb', line 53

def from_ecef(x, y, z)
  # Constants (WGS ellipsoid)
  a = WGS84_A
  e = WGS84_E
    
  b = Math::sqrt((a*a) * (1.0-(e*e)))
  ep = Math::sqrt(((a*a)-(b*b))/(b*b))
  
  p = Math::sqrt((x*x)+(y*y))
  th = Math::atan2(a*z, b*p)
  
  lon = Math::atan2(y, x)
  lat = Math::atan2((z+ep*ep*b*(Math::sin(th) ** 3)), (p-e*e*a*(Math::cos(th)**3)))
  
  n = a / Math::sqrt(1.0-e*e*(Math::sin(lat) ** 2))
  # alt = p / Math::cos(lat)-n
  
  return self.new(lat*R2D, lon*R2D)
end

Instance Method Details

#-(other) ⇒ Object



165
166
167
# File 'lib/geospatial/location.rb', line 165

def - other
  Distance.new(self.distance_from(other))
end

#bounding_box(distance, radius = EARTH_RADIUS) ⇒ Object

Raises:

  • (ArgumentError)


99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/geospatial/location.rb', line 99

def bounding_box(distance, radius = EARTH_RADIUS)
  raise ArgumentError.new("Invalid distance or radius") if distance < 0 or radius < 0

  # angular distance in radians on a great circle
  angular_distance = distance / radius

  min_latitude = (self.latitude * D2R) - angular_distance
  max_latitude = (self.latitude * D2R) + angular_distance

  if min_latitude > MIN_LATITUDE and max_latitude < MAX_LATITUDE
    longitude_delta = Math::asin(Math::sin(angular_distance) / Math::cos(self.latitude * D2R))
    
    min_longitude = (self.longitude * D2R) - longitude_delta
    min_longitude += 2.0 * Math::PI if (min_longitude < MIN_LONGITUDE)
    
    max_longitude = (self.longitude * D2R) + longitude_delta;
    max_longitude -= 2.0 * Math::PI if (max_longitude > MAX_LONGITUDE)
  else
    # a pole is within the distance
    min_latitude = [min_latitude, MIN_LATITUDE].max
    max_latitude = [max_latitude, MAX_LATITUDE].min
    
    min_longitude = MIN_LONGITUDE
    max_longitude = MAX_LONGITUDE
  end
  
  return {
    :latitude => Range.new(min_latitude * R2D, max_latitude * R2D),
    :longitude => Range.new(min_longitude * R2D, max_longitude * R2D),
  }
end

#distance_from(other) ⇒ Object

calculate distance in metres between us and something else ref: codingandweb.blogspot.co.nz/2012/04/calculating-distance-between-two-points.html



149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/geospatial/location.rb', line 149

def distance_from(other)
  rlong1 = self.longitude * D2R 
  rlat1 = self.latitude * D2R 
  rlong2 = other.longitude * D2R 
  rlat2 = other.latitude * D2R 
  
  dlon = rlong1 - rlong2
  dlat = rlat1 - rlat2
  
  a = Math::sin(dlat/2) ** 2 + Math::cos(rlat1) * Math::cos(rlat2) * Math::sin(dlon/2) ** 2
  c = 2 * Math::atan2(Math::sqrt(a), Math::sqrt(1-a))
  d = EARTH_RADIUS * c
  
  return d
end

#to_aObject



85
86
87
# File 'lib/geospatial/location.rb', line 85

def to_a
  [@longitude, @latitude]
end

#to_ecefObject

Converts latitude, longitude to ECEF coordinate system



132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/geospatial/location.rb', line 132

def to_ecef
  clon = Math::cos(lon * D2R)
  slon = Math::sin(lon * D2R)
  clat = Math::cos(lat * D2R)
  slat = Math::sin(lat * D2R)

  n = WGS84_A / Math::sqrt(1.0 - WGS84_E * WGS84_E * slat * slat)

  x = n * clat * clon
  y = n * clat * slon
  z = n * (1.0 - WGS84_E * WGS84_E) * slat
  
  return x, y, z
end

#to_sObject Also known as: inspect



89
90
91
# File 'lib/geospatial/location.rb', line 89

def to_s
  "#{self.class}[#{self.longitude.to_f}, #{self.latitude.to_f}]"
end

#valid?Boolean

Returns:

  • (Boolean)


81
82
83
# File 'lib/geospatial/location.rb', line 81

def valid?
  VALID_LONGITUDE.include?(longitude) and VALID_LATITUDE.include?(latitude)
end