distance_fox 0.1.3 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.travis.yml +1 -1
- data/Gemfile.lock +1 -1
- data/lib/distance_fox/calculations.rb +100 -98
- data/lib/distance_fox/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2afe2b7e3b59d3047f7b2ce181169f2a4fb3bcc882572ee66856468909f08ee3
|
|
4
|
+
data.tar.gz: 7e1c0b16d8c0d3fa05afc4ff02b2850ea40c231b9cd69c9e571a2094b7affd2a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7b56bd1db29afdd6e1f681b66c350c530e278ff750652a75d7f75dafbcd8bffba6b343d8109161fecbef15ff794a1951c0f99f5dcfab4e5ac9e35e287d7960f6
|
|
7
|
+
data.tar.gz: 6ce540bc79a13fa41a33f72926652925391f33f22de984a8800dda0d5278a98374fa20df1281052ed1a2a226a512413dfa561f6fd778077855fd699d60c96cce
|
data/.travis.yml
CHANGED
data/Gemfile.lock
CHANGED
|
@@ -1,119 +1,121 @@
|
|
|
1
1
|
require 'httparty'
|
|
2
2
|
|
|
3
3
|
module DistanceFox
|
|
4
|
-
|
|
4
|
+
class Calculations
|
|
5
|
+
EARTH_RADIUS = 6371.0
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
7
|
+
# Origin and destination can be:
|
|
8
|
+
#
|
|
9
|
+
# * an array of coordinates ([lat,lon])
|
|
10
|
+
# * an array of coordinates (['lat','lon'])
|
|
11
|
+
# * a geocodable address (string)
|
|
12
|
+
def self.linear_distance(origin, destination)
|
|
13
|
+
lat_origin, lon_origin = extract_coordinates origin
|
|
14
|
+
lat_destination, lon_destination = extract_coordinates destination
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
delta_lat = (lat_destination - lat_origin) * Math::PI / 180
|
|
17
|
+
delta_lon = (lon_destination - lon_origin) * Math::PI / 180
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
a = Math.sin(delta_lat / 2) *
|
|
20
|
+
Math.sin(delta_lat / 2) +
|
|
21
|
+
Math.cos(lat_origin * Math::PI / 180) *
|
|
22
|
+
Math.cos(lat_destination * Math::PI / 180) *
|
|
23
|
+
Math.sin(delta_lon / 2) * Math.sin(delta_lon / 2)
|
|
23
24
|
|
|
24
|
-
|
|
25
|
+
c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a))
|
|
25
26
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
d = EARTH_RADIUS * c
|
|
28
|
+
d.round(3)
|
|
29
|
+
end
|
|
29
30
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
31
|
+
##
|
|
32
|
+
# Linear Distance to nearest location from multiple locations
|
|
33
|
+
# Origin can be:
|
|
34
|
+
# * an array of float coordinates ([lat,lon])
|
|
35
|
+
# * an array of string coordinates (['lat','lon'])
|
|
36
|
+
#
|
|
37
|
+
# Destinations can be:
|
|
38
|
+
# * a hash of arrays ({['city' => 'City', 'coordinates' => ['lat','lon']]})
|
|
39
|
+
def self.nearest_linear_distance(origin, destinations)
|
|
40
|
+
origins_with_distance = []
|
|
41
|
+
origin_coordinates = extract_coordinates origin
|
|
42
|
+
destinations.each do |destination|
|
|
43
|
+
distance = linear_distance(origin_coordinates, destination['coordinates'])
|
|
44
|
+
origins_with_distance.push(
|
|
45
|
+
'destination' => destination['city'],
|
|
46
|
+
'distance' => distance,
|
|
47
|
+
'coordinates' => {
|
|
48
|
+
'origin' => origin_coordinates,
|
|
49
|
+
'destination' => destination['coordinates']
|
|
50
|
+
}
|
|
51
|
+
)
|
|
52
|
+
end
|
|
53
|
+
origins_with_distance.min_by { |key| key['distance'] }
|
|
51
54
|
end
|
|
52
|
-
origins_with_distance.min_by { |key| key['distance'] }
|
|
53
|
-
end
|
|
54
55
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
56
|
+
##
|
|
57
|
+
# Origin and destination can be:
|
|
58
|
+
#
|
|
59
|
+
# * an array of coordinates ([lat,lon])
|
|
60
|
+
# * an array of coordinates (['lat','lon'])
|
|
61
|
+
# * a geocodable address (string)
|
|
62
|
+
def self.driving_distance(origin, destination)
|
|
63
|
+
origin = extract_coordinates(origin).join(',')
|
|
64
|
+
destination = extract_coordinates(destination).join(',')
|
|
65
|
+
google_distance_query = "https://maps.googleapis.com/maps/api/distancematrix/json?mode=driving&origins=#{origin}&destinations=#{destination}&key=#{DistanceFox.configuration.api_key}"
|
|
66
|
+
google_distance_response = HTTParty.get(URI.escape(google_distance_query))
|
|
67
|
+
google_distance_response['rows'][0]['elements'][0]['distance']['value'].to_f / 1000
|
|
68
|
+
end
|
|
68
69
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
70
|
+
##
|
|
71
|
+
# Driving Distance to nearest location from multiple locations
|
|
72
|
+
#
|
|
73
|
+
# Origin can be:
|
|
74
|
+
# * an array of coordinates ([lat,lon])
|
|
75
|
+
# * an array of coordinates (['lat','lon'])
|
|
76
|
+
# * a geocodable address (string)
|
|
77
|
+
#
|
|
78
|
+
# Destinations can be:
|
|
79
|
+
# * a hash of arrays ({['city' => 'City', 'coordinates' => ['lat','lon']]})
|
|
80
|
+
def self.nearest_driving_distance(origin, destinations)
|
|
81
|
+
origin = origin.join(',')
|
|
82
|
+
destination = nearest_linear_distance(origin, destinations)['coordinates']['destination'].join(',')
|
|
83
|
+
driving_distance(origin, destination)
|
|
84
|
+
end
|
|
84
85
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
86
|
+
# Address can be:
|
|
87
|
+
# a geocodable address (string)
|
|
88
|
+
def self.geocode(address)
|
|
89
|
+
google_distance_response = HTTParty.get(URI.escape(google_distance_query))
|
|
90
|
+
case google_distance_response["results"]
|
|
91
|
+
when []
|
|
92
|
+
raise "Status: #{google_distance_response['status']}"
|
|
93
|
+
else
|
|
94
|
+
coordinates = google_distance_response['results'][0]['geometry']['location']
|
|
95
|
+
end
|
|
96
|
+
[coordinates['lat'], coordinates['lng']]
|
|
94
97
|
end
|
|
95
|
-
[coordinates['lat'], coordinates['lng']]
|
|
96
|
-
end
|
|
97
98
|
|
|
98
|
-
|
|
99
|
+
private
|
|
99
100
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
101
|
+
##
|
|
102
|
+
# Takes an object which is a [lat,lon] array or a geocodable string.
|
|
103
|
+
# Note that if a string is passed this may be a slow-
|
|
104
|
+
# running method and may return nil.
|
|
105
|
+
def self.extract_coordinates(point)
|
|
106
|
+
case point
|
|
107
|
+
when Array
|
|
108
|
+
if point.size == 2
|
|
109
|
+
lat, lon = point
|
|
110
|
+
if !lat.nil? && lat.respond_to?(:to_f) &&
|
|
111
|
+
!lon.nil? && lon.respond_to?(:to_f)
|
|
112
|
+
return [lat.to_f, lon.to_f]
|
|
113
|
+
end
|
|
112
114
|
end
|
|
115
|
+
when String
|
|
116
|
+
(point = geocode(point)) && (return point)
|
|
113
117
|
end
|
|
114
|
-
|
|
115
|
-
(point = geocode(point)) && (return point)
|
|
118
|
+
raise "#{point} is not geocodable"
|
|
116
119
|
end
|
|
117
|
-
raise "#{point} is not geocodable"
|
|
118
120
|
end
|
|
119
121
|
end
|
data/lib/distance_fox/version.rb
CHANGED