geo_ref.rb
2.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
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
72
73
74
75
76
77
78
79
80
81
82
83
84
module Noosfero::GeoRef
# May replace this module by http://www.postgresql.org/docs/9.3/static/earthdistance.html
EARTH_RADIUS = 6378 # aproximate in km
class << self
def dist(lat1, lng1, lat2, lng2)
def deg2rad(d); (d*Math::PI)/180; end
def c(n); Math.cos(n); end
def s(n); Math.sin(n); end
lat1 = deg2rad lat1
lat2 = deg2rad lat2
dlng = deg2rad(lng2) - deg2rad(lng1)
EARTH_RADIUS * Math.atan2(
Math.sqrt(
( c(lat2) * s(dlng) )**2 +
( c(lat1) * s(lat2) - s(lat1) * c(lat2) * c(dlng) )**2
),
s(lat1) * s(lat2) + c(lat1) * c(lat2) * c(dlng)
)
end
# Write a SQL expression to return the distance from a profile to a
# reference point, in kilometers.
# http://www.plumislandmedia.net/mysql/vicenty-great-circle-distance-formula
def sql_dist(ref_lat, ref_lng)
"2*PI()*#{EARTH_RADIUS}*(
DEGREES(
ATAN2(
SQRT(
POW(COS(RADIANS(#{ref_lat}))*SIN(RADIANS(#{ref_lng}-lng)),2) +
POW(
COS(RADIANS(lat)) * SIN(RADIANS(#{ref_lat})) - (
SIN(RADIANS(lat)) * COS(RADIANS(#{ref_lat})) * COS(RADIANS(#{ref_lng}-lng))
), 2
)
),
SIN(RADIANS(lat)) * SIN(RADIANS(#{ref_lat})) +
COS(RADIANS(lat)) * COS(RADIANS(#{ref_lat})) * COS(RADIANS(#{ref_lng}-lng))
)
)/360
)"
end
# Asks Google for the georef of a location.
def location_to_georef(location)
key = location.downcase
ll = Rails.cache.read key
return ll + [:CACHE] if ll.kind_of? Array
resp = RestClient.get 'https://maps.googleapis.com/maps/api/geocode/json?' +
'sensor=false&address=' + url_encode(location)
if resp.nil? || resp.code.to_i != 200
if ENV['RAILS_ENV'] == 'test'
print " Google Maps API fail (code #{resp ? resp.code : :nil}) "
else
Rails.logger.warn "Google Maps API request information for " +
"\"#{location}\" fail. (code #{resp ? resp.code : :nil})"
end
return [ 0, 0, "HTTP_FAIL_#{resp.code}".to_sym ] # do not cache failed response
else
json = JSON.parse resp.body
if json && (r=json['results']) && (r=r[0]) && (r=r['geometry']) &&
(r=r['location']) && r['lat']
ll = [ r['lat'], r['lng'], :SUCCESS ]
else
status = json['status'] || 'Undefined Error'
message = "Google Maps API cant find \"#{location}\" (#{status})"
if ENV['RAILS_ENV'] == 'test'
print " #{message} "
else
Rails.logger.warn message
end
ll = [ 0, 0, status.to_sym ]
end
Rails.cache.write key, ll
end
ll
end
end
end