Class: Cartier::Navigation

Inherits:
Object
  • Object
show all
Defined in:
lib/cartier/navigation.rb

Overview

Encapsulating class for Navigation calculations

Constant Summary collapse

EARTH_RADIUS =

radius in km

6371
RADIANS =
57.29578

Class Method Summary collapse

Class Method Details

.closest_point(location_here, array_of_locations = nil) ⇒ Object

  • Args :

    • location_here -> GPSLocation object representing current location

    • array_of_locations -> an Array of GPSLocation objects

  • Returns :

    • GPSLocation object representing closest location



55
56
57
58
59
# File 'lib/cartier/navigation.rb', line 55

def self.closest_point(location_here, array_of_locations=nil)
  array_of_locations.sort do |a, b| 
    self.haversine_distance(location_here, a) <=> self.haversine_distance(location_here, b) 
  end.first
end

.equirectangular_projection(location, destination) ⇒ Object

  • Args :

    • location -> GPSLocation object representing current location

    • longitude -> GPSLocation object representing current destination

  • Returns :

    • distance in km



35
36
37
38
39
40
41
42
43
44
45
# File 'lib/cartier/navigation.rb', line 35

def self.equirectangular_projection(location, destination)
  latitude_1 = (location.latitude.to_f) * Math::PI/180
  latitude_2 = (destination.latitude.to_f) * Math::PI/180
  
  longitude_1 = (location.longitude.to_f) * Math::PI/180
  longitude_2 = (destination.longitude.to_f) * Math::PI/180
  
  x = (longitude_2 - longitude_1) * Math.cos((latitude_1+latitude_2)/2)
  y = latitude_2 - latitude_1
  Math.sqrt(x*x + y*y) * EARTH_RADIUS
end

.get_bearing(location, destination) ⇒ Object

  • Args :

    • location -> GPSLocation object representing current location

    • destination -> GPSLocation object representing destination

  • Returns :

    • Bearing in Degrees (not radians)



69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/cartier/navigation.rb', line 69

def self.get_bearing(location, destination)
  location_long = location.longitude.to_f * Math::PI/180
  location_latitude = location.latitude.to_f * Math::PI/180
  destination_long = destination.longitude.to_f
  destination_latitude = destination.latitude.to_f
  
  delta_long = (destination_long - location_long) * Math::PI/180
  y = Math.sin(delta_long) * Math.cos(destination_latitude)
  x = Math.cos(location_latitude) * Math.sin(destination_latitude) - Math.sin(location_latitude) * Math.cos(destination_latitude) * Math.cos(delta_long)
  theta = (Math.atan2(y, x) / Math::PI) * 180
  (theta + 360) % 360
end

.get_destination_point(location, bearing, distance) ⇒ Object

  • Args :

    • location -> Cartier::GPSLocation

    • bearing -> Bearing in Degrees

    • distance -> Distance in km

  • Returns :

    • Cartier::GPSLocation object representing final point



119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/cartier/navigation.rb', line 119

def self.get_destination_point(location, bearing, distance)
  distance_in_radians = distance / EARTH_RADIUS
  bearing_in_radians = bearing * Math::PI/180
  
  latitude_1 = location.latitude.to_f * Math::PI/180
  longitude_1 = location.longitude.to_f * Math::PI/180
  
  latitude_2 = Math.asin( Math.sin(latitude_1)*Math.cos(distance_in_radians) + 
                    Math.cos(latitude_1)*Math.sin(distance_in_radians)*Math.cos(bearing_in_radians) )
  longitude_2 = longitude_1 + Math.atan2(Math.sin(bearing_in_radians)*Math.sin(distance_in_radians)*Math.cos(latitude_1), 
                           Math.cos(distance_in_radians)-Math.sin(latitude_1)*Math.sin(latitude_2))
  longitude_2 = (longitude_2+3*Math::PI) % (2*Math::PI) - Math::PI
  latitude_2 = latitude_2 * RADIANS
  longitude_2 = longitude_2 * RADIANS
  Cartier::GPSLocation.new(latitude_2.to_s, longitude_2.to_s)
end

.get_midpoint(location, destination) ⇒ Object

  • Args :

    • location -> GPSLocation object representing current location

    • destination -> GPSLocation object representing destination

  • Returns :

    • Cartier::GPSLocation object representing midpoint



91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/cartier/navigation.rb', line 91

def self.get_midpoint(location, destination)
  latitude_1 = location.latitude.to_f * Math::PI/180
  longitude_1 = location.longitude.to_f * Math::PI/180
  latitude_2 = destination.latitude.to_f * Math::PI/180
  delta_long = (destination.longitude.to_f - location.longitude.to_f) * Math::PI/180
  
  bx = Math.cos(latitude_2) * Math.cos(delta_long)
  by = Math.cos(latitude_2) * Math.sin(delta_long)

  latitude_3 = Math.atan2(Math.sin(latitude_1) + Math.sin(latitude_2), 
    Math.sqrt( (Math.cos(latitude_1)+bx)*(Math.cos(latitude_1)+bx) + by*by))
  longitude_3 = longitude_1 + Math.atan2(by, Math.cos(latitude_1) + bx)
  longitude_3 = (longitude_3+3*Math::PI) % (2*Math::PI) - Math::PI
  
  latitude_3 = latitude_3 * RADIANS
  longitude_3 = longitude_3 * RADIANS
  Cartier::GPSLocation.new(latitude_3.to_s, longitude_3.to_s)
end

.haversine_distance(location, destination) ⇒ Object

  • Args :

    • location -> GPSLocation object representing current location

    • longitude -> GPSLocation object representing current destination

  • Returns :

    • distance in km



16
17
18
19
20
21
22
23
24
25
26
# File 'lib/cartier/navigation.rb', line 16

def self.haversine_distance(location, destination)
  delta_lat = (destination.latitude.to_f - location.latitude.to_f) * Math::PI/180
  delta_long = (destination.longitude.to_f - location.longitude.to_f) * Math::PI/180

  latitude_1 = (location.latitude.to_f) * Math::PI/180
  latitude_2 = (destination.latitude.to_f) * Math::PI/180

  a = Math.sin(delta_lat/2)**2 + Math.sin(delta_long/2)**2 * Math.cos(latitude_1) * Math.cos(latitude_2)
  c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a))
  EARTH_RADIUS * c  
end