Module: Geocoder::Calculations
Instance Method Summary collapse
-
#distance_between(lat1, lon1, lat2, lon2, options = {}) ⇒ Object
Calculate the distance between two points on Earth (Haversine formula).
-
#geographic_center(points) ⇒ Object
Compute the geographic center (aka geographic midpoint, center of gravity) for an array of geocoded objects and/or [lat,lon] arrays (can be mixed).
-
#km_in_mi ⇒ Object
Conversion factor: km to mi.
-
#to_degrees(radians) ⇒ Object
Convert radians to degrees.
-
#to_radians(degrees) ⇒ Object
Convert degrees to radians.
Instance Method Details
#distance_between(lat1, lon1, lat2, lon2, options = {}) ⇒ Object
Calculate the distance between two points on Earth (Haversine formula). Takes two sets of coordinates and an options hash:
:units
-
:mi
(default) or:km
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
# File 'lib/geocoder/calculations.rb', line 11 def distance_between(lat1, lon1, lat2, lon2, = {}) # set default options [:units] ||= :mi # define conversion factors conversions = { :mi => 3956, :km => 6371 } # convert degrees to radians lat1 = to_radians(lat1) lon1 = to_radians(lon1) lat2 = to_radians(lat2) lon2 = to_radians(lon2) # compute distances dlat = (lat1 - lat2).abs dlon = (lon1 - lon2).abs a = (Math.sin(dlat / 2))**2 + Math.cos(lat1) * (Math.sin(dlon / 2))**2 * Math.cos(lat2) c = 2 * Math.atan2( Math.sqrt(a), Math.sqrt(1-a)) c * conversions[[:units]] end |
#geographic_center(points) ⇒ Object
Compute the geographic center (aka geographic midpoint, center of gravity) for an array of geocoded objects and/or [lat,lon] arrays (can be mixed). Any objects missing coordinates are ignored. Follows the procedure documented at www.geomidpoint.com/calculation.html.
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
# File 'lib/geocoder/calculations.rb', line 41 def geographic_center(points) # convert objects to [lat,lon] arrays and remove nils points = points.map{ |p| p.is_a?(Array) ? p : (p.geocoded?? p.read_coordinates : nil) }.compact # convert degrees to radians points.map!{ |p| [to_radians(p[0]), to_radians(p[1])] } # convert to Cartesian coordinates x = []; y = []; z = [] points.each do |p| x << Math.cos(p[0]) * Math.cos(p[1]) y << Math.cos(p[0]) * Math.sin(p[1]) z << Math.sin(p[0]) end # compute average coordinate values xa, ya, za = [x,y,z].map do |c| c.inject(0){ |tot,i| tot += i } / c.size.to_f end # convert back to latitude/longitude lon = Math.atan2(ya, xa) hyp = Math.sqrt(xa**2 + ya**2) lat = Math.atan2(za, hyp) # return answer in degrees [to_degrees(lat), to_degrees(lon)] end |
#km_in_mi ⇒ Object
Conversion factor: km to mi.
90 91 92 |
# File 'lib/geocoder/calculations.rb', line 90 def km_in_mi 0.621371192 end |
#to_degrees(radians) ⇒ Object
Convert radians to degrees.
83 84 85 |
# File 'lib/geocoder/calculations.rb', line 83 def to_degrees(radians) (radians * 180.0) / Math::PI end |
#to_radians(degrees) ⇒ Object
Convert degrees to radians.
76 77 78 |
# File 'lib/geocoder/calculations.rb', line 76 def to_radians(degrees) degrees * (Math::PI / 180) end |