Module: GeoTools::Location::ClassMethods

Defined in:
lib/geo_tools/location.rb

Instance Method Summary collapse

Instance Method Details

#acts_as_locationObject



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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
# File 'lib/geo_tools/location.rb', line 10

def acts_as_location
  include InstanceMethodsOnActivation

  validates_numericality_of_for :latitude_degrees,
                                :only_integer             => true,
                                :greater_than_or_equal_to => 0,
                                :less_than_or_equal_to    => 90,
                                :message                  => 'Degrees are invalid',
                                :for                      => :latitude

  validates_numericality_of_for :latitude_minutes,
                                :only_integer             => true,
                                :greater_than_or_equal_to => 0,
                                :less_than                => 60,
                                :message                  => 'Minutes are invalid',
                                :for                      => :latitude

  validates_numericality_of_for :latitude_decimal_minutes,
                                :only_integer              => true,
                                :greater_than_or_equal_to  => 0,
                                :message                   => 'Decimal minutes are invalid',
                                :for                       => :latitude

  validates_numericality_of_for :latitude_decimal_minutes_width,
                                :only_integer             => true,
                                :greater_than_or_equal_to => 0,
                                :for                      => :latitude

  validates_inclusion_of_for    :latitude_hemisphere,
                                :in      => %w( N S ),
                                :message => 'Hemisphere is invalid',
                                :for     => :latitude

  validates_numericality_of_for :longitude_degrees,
                                :only_integer             => true,
                                :greater_than_or_equal_to => 0,
                                :less_than_or_equal_to    => 180,
                                :message                  => 'Degrees are invalid',
                                :for                      => :longitude

  validates_numericality_of_for :longitude_minutes,
                                :only_integer             => true,
                                :greater_than_or_equal_to => 0,
                                :less_than                => 60,
                                :message                  => 'Minutes are invalid',
                                :for                      => :longitude

  validates_numericality_of_for :longitude_decimal_minutes,
                                :only_integer             => true,
                                :greater_than_or_equal_to => 0,
                                :message                  => 'Decimal minutes are invalid',
                                :for                      => :longitude

  validates_numericality_of_for :longitude_decimal_minutes_width,
                                :only_integer             => true,
                                :greater_than_or_equal_to => 0,
                                :for                      => :longitude

  validates_inclusion_of_for    :longitude_hemisphere,
                                :in      => %w( E W ),
                                :message => 'Hemisphere is invalid',
                                :for     => :longitude

  before_validation :set_empty_values

  # Returns all locations within the given bounding box, to an accuracy of 1 minute.
  #
  # This is useful for finding all locations within the area covered by a Google map.
  #
  # The parameters should be positive/negative floats.
  named_scope :within, lambda { |sw_lat, sw_lng, ne_lat, ne_lng|
    sw_lat_degs = sw_lat.to_i.abs
    sw_lat_mins = ((sw_lat - sw_lat.to_i) * 60.0).round.abs
    ne_lat_degs = ne_lat.to_i.abs
    ne_lat_mins = ((ne_lat - ne_lat.to_i) * 60.0).round.abs

    sw_lng_degs = sw_lng.to_i.abs
    sw_lng_mins = ((sw_lng - sw_lng.to_i) * 60.0).round.abs
    ne_lng_degs = ne_lng.to_i.abs
    ne_lng_mins = ((ne_lng - ne_lng.to_i) * 60.0).round.abs

    # Latitude conditions.
    if sw_lat > 0 && ne_lat > 0       # northern hemisphere
      condition_lat_h  = 'latitude_hemisphere = "N"'
      condition_lat_sw = ["(latitude_degrees > ?) OR (latitude_degrees = ? AND latitude_minutes >= ?)", sw_lat_degs, sw_lat_degs, sw_lat_mins]
      condition_lat_ne = ["(latitude_degrees < ?) OR (latitude_degrees = ? AND latitude_minutes <= ?)", ne_lat_degs, ne_lat_degs, ne_lat_mins]
      condition_lat    = merge_conditions condition_lat_h, condition_lat_sw, condition_lat_ne

    elsif sw_lat < 0 && ne_lat < 0    # southern hemisphere
      condition_lat_h  = 'latitude_hemisphere = "S"'
      condition_lat_sw = ["(latitude_degrees < ?) OR (latitude_degrees = ? AND latitude_minutes <= ?)", sw_lat_degs, sw_lat_degs, sw_lat_mins]
      condition_lat_ne = ["(latitude_degrees > ?) OR (latitude_degrees = ? AND latitude_minutes >= ?)", ne_lat_degs, ne_lat_degs, ne_lat_mins]
      condition_lat    = merge_conditions condition_lat_h, condition_lat_sw, condition_lat_ne

    elsif sw_lat <= 0 && ne_lat >= 0  # straddles equator
      condition_lat_h  = 'latitude_hemisphere = "S"'
      condition_lat_sw = ["(latitude_degrees < ?) OR (latitude_degrees = ? AND latitude_minutes <= ?)", sw_lat_degs, sw_lat_degs, sw_lat_mins]
      condition_lat_s  = merge_conditions condition_lat_h, condition_lat_sw

      condition_lat_h  = 'latitude_hemisphere = "N"'
      condition_lat_ne = ["(latitude_degrees < ?) OR (latitude_degrees = ? AND latitude_minutes <= ?)", ne_lat_degs, ne_lat_degs, ne_lat_mins]
      condition_lat_n  = merge_conditions condition_lat_h, condition_lat_ne

      condition_lat    = merge_or_conditions condition_lat_s, condition_lat_n
    end

    # Longitude conditions.
    if sw_lng > 0 && ne_lng > 0       # eastern hemisphere
      condition_lng_h  = 'longitude_hemisphere = "E"'
      condition_lng_sw = ["(longitude_degrees > ?) OR (longitude_degrees = ? AND longitude_minutes >= ?)", sw_lng_degs, sw_lng_degs, sw_lng_mins]
      condition_lng_ne = ["(longitude_degrees < ?) OR (longitude_degrees = ? AND longitude_minutes <= ?)", ne_lng_degs, ne_lng_degs, ne_lng_mins]
      condition_lng    = merge_conditions condition_lng_h, condition_lng_sw, condition_lng_ne

    elsif sw_lng < 0 && ne_lng < 0    # western hemisphere
      condition_lng_h  = 'longitude_hemisphere = "W"'
      condition_lng_sw = ["(longitude_degrees < ?) OR (longitude_degrees = ? AND longitude_minutes <= ?)", sw_lng_degs, sw_lng_degs, sw_lng_mins]
      condition_lng_ne = ["(longitude_degrees > ?) OR (longitude_degrees = ? AND longitude_minutes >= ?)", ne_lng_degs, ne_lng_degs, ne_lng_mins]
      condition_lng    = merge_conditions condition_lng_h, condition_lng_sw, condition_lng_ne

    elsif sw_lng <= 0 && ne_lng >= 0  # straddles prime meridian
      condition_lng_h  = 'longitude_hemisphere = "W"'
      condition_lng_sw = ["(longitude_degrees < ?) OR (longitude_degrees = ? AND longitude_minutes <= ?)", sw_lng_degs, sw_lng_degs, sw_lng_mins]
      condition_lng_w  = merge_conditions condition_lng_h, condition_lng_sw

      condition_lng_h  = 'longitude_hemisphere = "E"'
      condition_lng_ne = ["(longitude_degrees < ?) OR (longitude_degrees = ? AND longitude_minutes <= ?)", ne_lng_degs, ne_lng_degs, ne_lng_mins]
      condition_lng_e  = merge_conditions condition_lng_h, condition_lng_ne

      condition_lng    = merge_or_conditions condition_lng_w, condition_lng_e
    end

    # Combined latitude and longitude conditions.
    {:conditions => merge_conditions(condition_lat, condition_lng)}
  }

  private

  # Merges conditions so that the result is a valid +condition+.
  # Adapted from ActiveRecord::Base#merge_conditions.
  def merge_or_conditions(*conditions)
    segments = []

    conditions.each do |condition|
      unless condition.blank?
        sql = sanitize_sql(condition)
        segments << sql unless sql.blank?
      end
    end

    "(#{segments.join(') OR (')})" unless segments.empty?
  end

end

#merge_or_conditions(*conditions) ⇒ Object

Merges conditions so that the result is a valid condition. Adapted from ActiveRecord::Base#merge_conditions.



149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/geo_tools/location.rb', line 149

def merge_or_conditions(*conditions)
  segments = []

  conditions.each do |condition|
    unless condition.blank?
      sql = sanitize_sql(condition)
      segments << sql unless sql.blank?
    end
  end

  "(#{segments.join(') OR (')})" unless segments.empty?
end