From b982bc6b19a3b14eba653088d917c6fe514db396 Mon Sep 17 00:00:00 2001 From: Tom Hughes Date: Wed, 20 Jun 2007 17:04:29 +0000 Subject: [PATCH] Make "nearby users" show all those within 50km rather than all those within a degree of latitude and longitude. --- app/models/user.rb | 22 +++++++++++++++------- app/views/user/account.rhtml | 4 +++- app/views/user/view.rhtml | 3 ++- lib/osm.rb | 28 ++++++++++++++++++++++++++++ 4 files changed, 48 insertions(+), 9 deletions(-) diff --git a/app/models/user.rb b/app/models/user.rb index 92d47d5ff..66669f95a 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -59,13 +59,21 @@ class User < ActiveRecord::Base return el1 end - def nearby(lat_range=1, lon_range=1) - if self.home_lon and self.home_lat - nearby = User.find(:all, :conditions => "#{self.home_lon} > home_lon - #{lon_range} and #{self.home_lon} < home_lon + #{lon_range} and #{self.home_lat} > home_lat - #{lat_range} and #{self.home_lat} < home_lat + #{lat_range} and data_public = 1 and id != #{self.id}") - else - nearby = [] - end - return nearby + def nearby(radius = 50) + if self.home_lon and self.home_lat + gc = OSM::GreatCircle.new(self.home_lat, self.home_lon) + bounds = gc.bounds(radius) + nearby = User.find(:all, :conditions => "home_lat between #{bounds[:minlat]} and #{bounds[:maxlat]} and home_lon between #{bounds[:minlon]} and #{bounds[:maxlon]} and data_public = 1 and id != #{self.id}") + nearby.delete_if { |u| gc.distance(u.home_lat, u.home_lon) > radius } + nearby.sort! { |u1,u2| gc.distance(u1.home_lat, u1.home_lon) <=> gc.distance(u2.home_lat, u2.home_lon) } + else + nearby = [] + end + return nearby + end + + def distance(nearby_user) + return OSM::GreatCircle.new(self.home_lat, self.home_lon).distance(nearby_user.home_lat, nearby_user.home_lon) end def self.has_messages? diff --git a/app/views/user/account.rhtml b/app/views/user/account.rhtml index cd38cc67f..5014b43af 100644 --- a/app/views/user/account.rhtml +++ b/app/views/user/account.rhtml @@ -34,13 +34,15 @@ + - <% @user.nearby(1,1).each do |nearby| %> + <% @user.nearby.each do |nearby| %> <% nearest_str += "nearest.push( { 'display_name' : '#{nearby.display_name}', 'home_lat' : #{nearby.home_lat}, 'home_lon' : #{nearby.home_lon} } );\n" %> + <%end%> diff --git a/app/views/user/view.rhtml b/app/views/user/view.rhtml index 7bc75a62f..862f802ce 100644 --- a/app/views/user/view.rhtml +++ b/app/views/user/view.rhtml @@ -75,9 +75,10 @@ There are no users who admit to mapping nearby. <% else %>
NameDistance Contact
<%= link_to nearby.display_name, :controller => 'user', :action => 'view', :display_name => nearby.display_name %><%= @user.distance(nearby).round %>km away <%= link_to 'send message', :controller => 'message', :action => 'new', :user_id => nearby.id %>
- <% @this_user.nearby(1,1).each do |nearby| %> + <% @this_user.nearby.each do |nearby| %> + <%end%> diff --git a/lib/osm.rb b/lib/osm.rb index 40ec9da3d..ae8e70896 100644 --- a/lib/osm.rb +++ b/lib/osm.rb @@ -241,6 +241,34 @@ module OSM end + class GreatCircle + include Math + + # initialise with a base position + def initialize(lat, lon) + @lat = lat * PI / 180 + @lon = lon * PI / 180 + end + + # get the distance from the base position to a given position + def distance(lat, lon) + lat = lat * PI / 180 + lon = lon * PI / 180 + return 6372.795 * 2 * asin(sqrt(sin((lat - @lat) / 2) ** 2 + cos(@lat) * cos(lat) * sin((lon - @lon)/2) ** 2)) + end + + # get the worst case bounds for a given radius from the base position + def bounds(radius) + latradius = 2 * asin(sqrt(sin(radius / 6372.795 / 2) ** 2)) + lonradius = 2 * asin(sqrt(sin(radius / 6372.795 / 2) ** 2 / cos(@lat) ** 2)) + minlat = (@lat - latradius) * 180 / PI + maxlat = (@lat + latradius) * 180 / PI + minlon = (@lon - lonradius) * 180 / PI + maxlon = (@lon + lonradius) * 180 / PI + return { :minlat => minlat, :maxlat => maxlat, :minlon => minlon, :maxlon => maxlon } + end + end + class GeoRSS def initialize(feed_title='OpenStreetMap GPS Traces', feed_description='OpenStreetMap GPS Traces', feed_url='http://www.openstreetmap.org/traces/') @doc = XML::Document.new -- 2.43.2
<%= link_to nearby.display_name, :controller => 'user', :action => 'view', :display_name => nearby.display_name %><%= @this_user.distance(nearby).round %>km away (<%= link_to 'send message', :controller => 'message', :action => 'new', :user_id => nearby.id %>)