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