Skip to content

Commit

Permalink
changed to qualified column names for lat/lng, and added Array#sort_b…
Browse files Browse the repository at this point in the history
…y_distance_from

git-svn-id: http://geokit.rubyforge.org/svn/trunk@36 9265c765-0211-4c68-b2df-6d1bd6e20c4d
  • Loading branch information
lewisac committed Jun 19, 2007
1 parent 47e3d0c commit 83065dc
Showing 1 changed file with 31 additions and 14 deletions.
45 changes: 31 additions & 14 deletions lib/geo_kit/acts_as_mappable.rb
Expand Up @@ -54,12 +54,14 @@ def acts_as_mappable(options = {})
send :include, Mappable

# Handle class variables.
cattr_accessor :distance_column_name, :default_units, :default_formula, :lat_column_name, :lng_column_name
cattr_accessor :distance_column_name, :default_units, :default_formula, :lat_column_name, :lng_column_name, :qualified_lat_column_name, :qualified_lng_column_name
self.distance_column_name = options[:distance_column_name] || 'distance'
self.default_units = options[:default_units] || GeoKit::default_units
self.default_formula = options[:default_formula] || GeoKit::default_formula
self.lat_column_name = options[:lat_column_name] || 'lat'
self.lng_column_name = options[:lng_column_name] || 'lng'
self.qualified_lat_column_name = "#{table_name}.#{lat_column_name}"
self.qualified_lng_column_name = "#{table_name}.#{lng_column_name}"
if options.include?(:auto_geocode) && options[:auto_geocode]
# if the form auto_geocode=>true is used, let the defaults take over by suppling an empty hash
options[:auto_geocode] = {} if options[:auto_geocode] == true
Expand Down Expand Up @@ -266,7 +268,7 @@ def augment_conditions(current_conditions,sql)
# NOTE: does not account for international date line yet.
def apply_bounds_conditions(options,bounds)
sw,ne=bounds
bounds_sql="#{lat_column_name}>#{sw.lat} AND #{lat_column_name}<#{ne.lat} AND #{lng_column_name}>#{sw.lng} AND #{lng_column_name}<#{ne.lng}"
bounds_sql="#{qualified_lat_column_name}>#{sw.lat} AND #{qualified_lat_column_name}<#{ne.lat} AND #{qualified_lng_column_name}>#{sw.lng} AND #{qualified_lng_column_name}<#{ne.lng}"
options[:conditions]=augment_conditions(options[:conditions],bounds_sql)
end

Expand Down Expand Up @@ -359,15 +361,15 @@ def sphere_distance_sql(origin, units)
case connection.adapter_name.downcase
when "mysql"
sql=<<-SQL_END
(ACOS(COS(#{lat})*COS(#{lng})*COS(RADIANS(#{lat_column_name}))*COS(RADIANS(#{lng_column_name}))+
COS(#{lat})*SIN(#{lng})*COS(RADIANS(#{lat_column_name}))*SIN(RADIANS(#{lng_column_name}))+
SIN(#{lat})*SIN(RADIANS(#{lat_column_name})))*#{multiplier})
(ACOS(COS(#{lat})*COS(#{lng})*COS(RADIANS(#{qualified_lat_column_name}))*COS(RADIANS(#{qualified_lng_column_name}))+
COS(#{lat})*SIN(#{lng})*COS(RADIANS(#{qualified_lat_column_name}))*SIN(RADIANS(#{qualified_lng_column_name}))+
SIN(#{lat})*SIN(RADIANS(#{qualified_lat_column_name})))*#{multiplier})
SQL_END
when "postgresql"
sql=<<-SQL_END
(ACOS(COS(#{lat})*COS(#{lng})*COS(RADIANS(#{lat_column_name}))*COS(RADIANS(#{lng_column_name}))+
COS(#{lat})*SIN(#{lng})*COS(RADIANS(#{lat_column_name}))*SIN(RADIANS(#{lng_column_name}))+
SIN(#{lat})*SIN(RADIANS(#{lat_column_name})))*#{multiplier})
(ACOS(COS(#{lat})*COS(#{lng})*COS(RADIANS(#{qualified_lat_column_name}))*COS(RADIANS(#{qualified_lng_column_name}))+
COS(#{lat})*SIN(#{lng})*COS(RADIANS(#{qualified_lat_column_name}))*SIN(RADIANS(#{qualified_lng_column_name}))+
SIN(#{lat})*SIN(RADIANS(#{qualified_lat_column_name})))*#{multiplier})
SQL_END
else
sql = "unhandled #{connection.adapter_name.downcase} adapter"
Expand All @@ -382,13 +384,13 @@ def flat_distance_sql(origin, units)
case connection.adapter_name.downcase
when "mysql"
sql=<<-SQL_END
SQRT(POW(#{lat_degree_units}*(#{origin.lat}-#{lat_column_name}),2)+
POW(#{lng_degree_units}*(#{origin.lng}-#{lng_column_name}),2))
SQRT(POW(#{lat_degree_units}*(#{origin.lat}-#{qualified_lat_column_name}),2)+
POW(#{lng_degree_units}*(#{origin.lng}-#{qualified_lng_column_name}),2))
SQL_END
when "postgresql"
sql=<<-SQL_END
SQRT(POW(#{lat_degree_units}*(#{origin.lat}-#{lat_column_name}),2)+
POW(#{lng_degree_units}*(#{origin.lng}-#{lng_column_name}),2))
SQRT(POW(#{lat_degree_units}*(#{origin.lat}-#{qualified_lat_column_name}),2)+
POW(#{lng_degree_units}*(#{origin.lng}-#{qualified_lng_column_name}),2))
SQL_END
else
sql = "unhandled #{connection.adapter_name.downcase} adapter"
Expand All @@ -401,7 +403,7 @@ def flat_distance_sql(origin, units)
def extract_latitude(point)
return point.lat if point.respond_to?(:lat)
return point.latitude if point.respond_to?(:latitude)
return point.send(lat_column_name) if point.instance_of?(self)
return point.send(qualified_lat_column_name) if point.instance_of?(self)
end

# Extract the longitude from the origin by trying the lng or longitude methods first
Expand All @@ -425,4 +427,19 @@ def normalize_point_to_lat_lng(point)
end
end
end
end
end

# Extend Array with a sort_by_distance method.
# This method creates a "distance" attribute on each object,
# calculates the distance from the passed origin,
# and finally sorts the array by the resulting distance.
class Array
def sort_by_distance_from(origin, opts={})
distance_attribute_name = opts.delete(:distance_attribute_name) || 'distance'
self.each do |e|
e.class.send(:attr_accessor, distance_attribute_name) if !e.respond_to? "#{distance_attribute_name}="
e.send("#{distance_attribute_name}=", origin.distance_to(e,opts))
end
self.sort!{|a,b|a.send(distance_attribute_name) <=> b.send(distance_attribute_name)}
end
end

0 comments on commit 83065dc

Please sign in to comment.