Location queries for a model
// when PostGIS is not available (when using MySQL for example)
1 2 def self.deg2rad(deg) 3 (deg * Math::PI / 180) 4 end 5 6 def self.rad2deg(rad) 7 (rad * 180 / Math::PI) 8 end 9 10 def self.acos(rad) 11 Math.atan2(Math.sqrt(1 - rad**2), rad) 12 end 13 14 def self.distance_in_miles(loc1, loc2) 15 lat1 = loc1.latitude 16 lon1 = loc1.longitude 17 lat2 = loc2.latitude 18 lon2 = loc2.longitude 19 theta = lon1 - lon2 20 21 dist = Math.sin(self.deg2rad(lat1)) * Math.sin(deg2rad(lat2)) 22 + Math.cos(self.deg2rad(lat1)) * Math.cos(self.deg2rad(lat2)) * Math.cos(deg2rad(theta)) 23 24 dist = self.rad2deg(self.acos(dist)) 25 26 (dist * 60 * 1.1515).round #distance in miles 27 end 28 29 def miles_to(location) 30 Location.distance_in_miles(self, location) 31 end 32 33 def self.locationArea(location, miles) 34 radius = miles.to_f 35 latR = radius / ((6076 / 5280) * 60) 36 lonR = radius / (((Math.cos(location.latitude * Math::PI / 180) * 6076) / 5280) * 60) 37 38 { 39 :min_latitude => location.latitude - latR, 40 :min_longitude => location.longitude - lonR, 41 :max_latitude => location.latitude + latR, 42 :max_longitude => location.longitude + lonR 43 } 44 end 45 46 def self.location_ids_in_range(location, miles) 47 la = Location.locationArea(location, miles) 48 Location.find(:all, 49 :select => "locations.id", 50 :conditions => ["locations.latitude <= ? and locations.latitude >= ? " + \ 51 " AND locations.longitude >= ? and locations.longitude <= ?", 52 la[:max_latitude], la[:min_latitude], la[:min_longitude], la[:max_longitude] 53 ] 54 ).collect { |l| l.id } 55 end 56 57 def self.locations_in_range(location, miles) 58 la = Location.locationArea(location, miles) 59 Location.find(:all, 60 :conditions => ["locations.latitude <= ? and locations.latitude >= ? " + \ 61 " AND locations.longitude >= ? and locations.longitude <= ?", 62 la[:max_latitude], la[:min_latitude], la[:min_longitude], la[:max_longitude] 63 ] 64 ) 65 end