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.
 
 
 
 
 

74 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. f.title as feed_title,
  24. ( #{EARTH_RADIUS_METRES}
  25. * acos( cos( radians('#{lat}') )
  26. * cos( radians( p.lat ) )
  27. * cos( radians( p.lon )
  28. - radians('#{lon}') )
  29. + sin( radians('#{lat}') )
  30. * sin( radians( p.lat ) ) ) )
  31. As distance
  32. FROM posts p
  33. INNER JOIN feeds f
  34. ON p.feed_id = f.id
  35. WHERE
  36. p.id IN
  37. ( -- Subquery returns a list of post_ids for posts on this layer
  38. SELECT p.id
  39. FROM subscriptions s
  40. INNER JOIN feeds f
  41. ON s.feed_id = f.id
  42. INNER JOIN posts p
  43. ON p.feed_id = f.id
  44. WHERE s.layer_id = #{layer_id}
  45. )
  46. AND
  47. (
  48. #{EARTH_RADIUS_METRES}
  49. * acos( cos( radians('#{lat}') )
  50. * cos( radians( p.lat ) )
  51. * cos( radians( p.lon )
  52. - radians('#{lon}') )
  53. + sin( radians('#{lat}') )
  54. * sin( radians( p.lat ) ) )
  55. )
  56. <= #{radius_metres}
  57. ORDER BY distance
  58. ENDQUERY
  59. )
  60. end
  61. end