GeoRSS aggregator and Layar augmented reality server
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

75 lines
1.8 KiB

  1. class Post < ActiveRecord::Base
  2. belongs_to :feed
  3. validates :title, :presence => true
  4. validates :lat, :numericality => { :greater_than_or_equal_to => -90, :less_than_or_equal_to => 90 }
  5. validates :lon, :numericality => { :greater_than_or_equal_to => -180, :less_than_or_equal_to => 180 }
  6. EARTH_RADIUS_METRES = 6378000
  7. def self.near(lat, lon, radius_metres, layer_id)
  8. # Santize inputs. Is this necessary?
  9. lat = lat.to_f
  10. lon = lon.to_f
  11. radius_metres = radius_metres.to_i
  12. layer_id = layer_id.to_i
  13. # Calculate distance using the Haversine formula
  14. self.find_by_sql(<<-ENDQUERY
  15. SELECT
  16. p.id,
  17. p.title,
  18. p.summary,
  19. p.url,
  20. p.lat,
  21. p.lon,
  22. p.published,
  23. p.feed_id,
  24. f.title as feed_title,
  25. ( #{EARTH_RADIUS_METRES}
  26. * acos( cos( radians('#{lat}') )
  27. * cos( radians( p.lat ) )
  28. * cos( radians( p.lon )
  29. - radians('#{lon}') )
  30. + sin( radians('#{lat}') )
  31. * sin( radians( p.lat ) ) ) )
  32. As distance
  33. FROM posts p
  34. INNER JOIN feeds f
  35. ON p.feed_id = f.id
  36. WHERE
  37. p.id IN
  38. ( -- Subquery returns a list of post_ids for posts on this layer
  39. SELECT p.id
  40. FROM subscriptions s
  41. INNER JOIN feeds f
  42. ON s.feed_id = f.id
  43. INNER JOIN posts p
  44. ON p.feed_id = f.id
  45. WHERE s.layer_id = #{layer_id}
  46. )
  47. AND
  48. (
  49. #{EARTH_RADIUS_METRES}
  50. * acos( cos( radians('#{lat}') )
  51. * cos( radians( p.lat ) )
  52. * cos( radians( p.lon )
  53. - radians('#{lon}') )
  54. + sin( radians('#{lat}') )
  55. * sin( radians( p.lat ) ) )
  56. )
  57. <= #{radius_metres}
  58. ORDER BY distance
  59. ENDQUERY
  60. )
  61. end
  62. end