geokit-rails 2.0.1 → 2.3.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of geokit-rails might be problematic. Click here for more details.
- checksums.yaml +6 -14
- data/.gitignore +37 -0
- data/.travis.yml +29 -0
- data/CHANGELOG.md +96 -0
- data/CONFIG.markdown +67 -0
- data/Gemfile +3 -0
- data/MIT-LICENSE +20 -0
- data/README.markdown +726 -0
- data/Rakefile +17 -0
- data/gemfiles/rails3.gemfile +7 -0
- data/gemfiles/rails4.gemfile +8 -0
- data/gemfiles/rails5.gemfile +8 -0
- data/geokit-rails.gemspec +33 -0
- data/lib/generators/geokit_rails/install_generator.rb +13 -0
- data/lib/generators/templates/geokit_config.rb +100 -0
- data/lib/geokit-rails.rb +0 -1
- data/lib/geokit-rails/acts_as_mappable.rb +87 -37
- data/lib/geokit-rails/adapters/oracleenhanced.rb +32 -0
- data/lib/geokit-rails/adapters/sqlite.rb +2 -2
- data/lib/geokit-rails/adapters/sqlserver.rb +19 -17
- data/lib/geokit-rails/geocoder_control.rb +7 -6
- data/lib/geokit-rails/ip_geocode_lookup.rb +17 -13
- data/lib/geokit-rails/railtie.rb +0 -1
- data/lib/geokit-rails/version.rb +1 -1
- data/test/acts_as_mappable_test.rb +30 -6
- data/test/boot.rb +3 -3
- data/test/fixtures/companies.yml +3 -1
- data/test/fixtures/custom_locations.yml +8 -1
- data/test/fixtures/locations.yml +8 -1
- data/test/schema.rb +1 -0
- data/test/test_helper.rb +17 -5
- metadata +120 -92
- data/lib/geokit-rails/defaults.rb +0 -21
- data/test/mysql-debug.log +0 -1057
- data/test/mysql2-debug.log +0 -2758
- data/test/mysql2spatial-debug.log +0 -3619
- data/test/postgres-debug.log +0 -1
- data/test/postgresql-debug.log +0 -1
- data/test/sqlite-debug.log +0 -67286
- data/test/test.sqlite3 +0 -0
data/Rakefile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
Bundler::GemHelper.install_tasks
|
3
|
+
|
4
|
+
require 'rdoc/task'
|
5
|
+
Rake::RDocTask.new do |rdoc|
|
6
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
7
|
+
|
8
|
+
rdoc.rdoc_dir = 'rdoc'
|
9
|
+
rdoc.title = "geokit-rails #{version}"
|
10
|
+
rdoc.rdoc_files.include('README*')
|
11
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
12
|
+
end
|
13
|
+
|
14
|
+
load 'test/tasks.rake'
|
15
|
+
|
16
|
+
desc 'Default: run unit tests.'
|
17
|
+
task :default => :test
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path("../lib/geokit-rails/version", __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |spec|
|
5
|
+
spec.name = "geokit-rails"
|
6
|
+
spec.version = GeokitRails::VERSION
|
7
|
+
spec.authors = ["Michael Noack", "Andre Lewis", "Bill Eisenhauer", "Jeremy Lecour"]
|
8
|
+
spec.email = ["michael+geokit@noack.com.au", "andre@earthcode.com", "bill_eisenhauer@yahoo.com", "jeremy.lecour@gmail.com"]
|
9
|
+
spec.summary = "Integrate Geokit with Rails"
|
10
|
+
spec.description = "Official Geokit plugin for Rails/ActiveRecord. Provides location-based goodness for your Rails app. Requires the Geokit gem."
|
11
|
+
spec.summary = "Geokit helpers for rails apps."
|
12
|
+
spec.homepage = "http://github.com/geokit/geokit-rails"
|
13
|
+
spec.license = "MIT"
|
14
|
+
|
15
|
+
spec.files = `git ls-files`.split($/)
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.add_dependency 'rails', '>= 3.0'
|
21
|
+
spec.add_dependency 'geokit', '~> 1.5'
|
22
|
+
spec.add_development_dependency "bundler", "> 1.0"
|
23
|
+
spec.add_development_dependency "simplecov", "~> 0.16.1"
|
24
|
+
spec.add_development_dependency "simplecov-rcov"
|
25
|
+
spec.add_development_dependency 'rake'
|
26
|
+
spec.add_development_dependency 'test-unit'
|
27
|
+
spec.add_development_dependency "mocha", "~> 0.9"
|
28
|
+
spec.add_development_dependency 'coveralls'
|
29
|
+
spec.add_development_dependency "mysql2", "~> 0.2"
|
30
|
+
spec.add_development_dependency "activerecord-mysql2spatial-adapter"
|
31
|
+
spec.add_development_dependency "pg", "~> 0.10"
|
32
|
+
spec.add_development_dependency "sqlite3"
|
33
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module GeokitRails
|
2
|
+
module Generators
|
3
|
+
class InstallGenerator < Rails::Generators::Base
|
4
|
+
source_root File.expand_path("../../templates", __FILE__)
|
5
|
+
|
6
|
+
desc "Creates a sample Geokit initializer."
|
7
|
+
|
8
|
+
def copy_initializer
|
9
|
+
copy_file "geokit_config.rb", "config/initializers/geokit_config.rb"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
# These defaults are used in Geokit::Mappable.distance_to and acts_as_mappable
|
2
|
+
Geokit::default_units = :miles # others :kms, :nms, :meters
|
3
|
+
Geokit::default_formula = :sphere
|
4
|
+
|
5
|
+
# This is the timeout value in seconds to be used for calls to the geocoder web
|
6
|
+
# services. For no timeout at all, comment out the setting. The timeout unit
|
7
|
+
# is in seconds.
|
8
|
+
Geokit::Geocoders::request_timeout = 3
|
9
|
+
|
10
|
+
# This setting can be used if web service calls must be routed through a proxy.
|
11
|
+
# These setting can be nil if not needed, otherwise, a valid URI must be
|
12
|
+
# filled in at a minimum. If the proxy requires authentication, the username
|
13
|
+
# and password can be provided as well.
|
14
|
+
# Geokit::Geocoders::proxy = 'https://user:password@host:port'
|
15
|
+
|
16
|
+
# This is your yahoo application key for the Yahoo Geocoder.
|
17
|
+
# See http://developer.yahoo.com/faq/index.html#appid
|
18
|
+
# and http://developer.yahoo.com/maps/rest/V1/geocode.html
|
19
|
+
# Geokit::Geocoders::YahooGeocoder.key = 'REPLACE_WITH_YOUR_YAHOO_KEY'
|
20
|
+
# Geokit::Geocoders::YahooGeocoder.secret = 'REPLACE_WITH_YOUR_YAHOO_SECRET'
|
21
|
+
|
22
|
+
# This is your Google Maps geocoder keys (all optional).
|
23
|
+
# See http://www.google.com/apis/maps/signup.html
|
24
|
+
# and http://www.google.com/apis/maps/documentation/#Geocoding_Examples
|
25
|
+
# Geokit::Geocoders::GoogleGeocoder.client_id = ''
|
26
|
+
# Geokit::Geocoders::GoogleGeocoder.cryptographic_key = ''
|
27
|
+
# Geokit::Geocoders::GoogleGeocoder.channel = ''
|
28
|
+
|
29
|
+
# You can also use the free API key instead of signed requests
|
30
|
+
# See https://developers.google.com/maps/documentation/geocoding/#api_key
|
31
|
+
# Geokit::Geocoders::GoogleGeocoder.api_key = ''
|
32
|
+
|
33
|
+
# You can also set multiple API KEYS for different domains that may be directed
|
34
|
+
# to this same application.
|
35
|
+
# The domain from which the current user is being directed will automatically
|
36
|
+
# be updated for Geokit via
|
37
|
+
# the GeocoderControl class, which gets it's begin filter mixed
|
38
|
+
# into the ActionController.
|
39
|
+
# You define these keys with a Hash as follows:
|
40
|
+
# Geokit::Geocoders::google = {
|
41
|
+
# 'rubyonrails.org' => 'RUBY_ON_RAILS_API_KEY',
|
42
|
+
# ' ruby-docs.org' => 'RUBY_DOCS_API_KEY' }
|
43
|
+
|
44
|
+
# This is your username and password for geocoder.us.
|
45
|
+
# To use the free service, the value can be set to nil or false. For
|
46
|
+
# usage tied to an account, the value should be set to username:password.
|
47
|
+
# See http://geocoder.us
|
48
|
+
# and http://geocoder.us/user/signup
|
49
|
+
# Geokit::Geocoders::UsGeocoder.key = 'username:password'
|
50
|
+
|
51
|
+
# This is your authorization key for geocoder.ca.
|
52
|
+
# To use the free service, the value can be set to nil or false. For
|
53
|
+
# usage tied to an account, set the value to the key obtained from
|
54
|
+
# Geocoder.ca.
|
55
|
+
# See http://geocoder.ca
|
56
|
+
# and http://geocoder.ca/?register=1
|
57
|
+
# Geokit::Geocoders::CaGeocoder.key = 'KEY'
|
58
|
+
|
59
|
+
# This is your username key for geonames.
|
60
|
+
# To use this service either free or premium, you must register a key.
|
61
|
+
# See http://www.geonames.org
|
62
|
+
# Geokit::Geocoders::GeonamesGeocoder.key = 'KEY'
|
63
|
+
|
64
|
+
# Most other geocoders need either no setup or a key
|
65
|
+
# Geokit::Geocoders::BingGeocoder.key = ''
|
66
|
+
# Geokit::Geocoders::MapQuestGeocoder.key = ''
|
67
|
+
# Geokit::Geocoders::YandexGeocoder.key = ''
|
68
|
+
# Geokit::Geocoders::MapboxGeocoder.key = 'ACCESS_TOKEN'
|
69
|
+
# Geokit::Geocoders::OpencageGeocoder.key = 'some_api_key'
|
70
|
+
|
71
|
+
# Geonames has a free service and a premium service, each using a different URL
|
72
|
+
# GeonamesGeocoder.premium = true will use http://ws.geonames.net (premium)
|
73
|
+
# GeonamesGeocoder.premium = false will use http://api.geonames.org (free)
|
74
|
+
# Geokit::Geocoders::GeonamesGeocoder.premium = false
|
75
|
+
|
76
|
+
# require "external_geocoder.rb"
|
77
|
+
# Please see the section "writing your own geocoders" for more information.
|
78
|
+
# Geokit::Geocoders::external_key = 'REPLACE_WITH_YOUR_API_KEY'
|
79
|
+
|
80
|
+
# This is the order in which the geocoders are called in a failover scenario
|
81
|
+
# If you only want to use a single geocoder, put a single symbol in the array.
|
82
|
+
# Valid symbols are :google, :yahoo, :us, and :ca.
|
83
|
+
# Be aware that there are Terms of Use restrictions on how you can use the
|
84
|
+
# various geocoders. Make sure you read up on relevant Terms of Use for each
|
85
|
+
# geocoder you are going to use.
|
86
|
+
# Geokit::Geocoders::provider_order = [:google,:us]
|
87
|
+
|
88
|
+
# The IP provider order. Valid symbols are :ip,:geo_plugin.
|
89
|
+
# As before, make sure you read up on relevant Terms of Use for each.
|
90
|
+
# Geokit::Geocoders::ip_provider_order = [:external,:geo_plugin,:ip]
|
91
|
+
|
92
|
+
# Disable HTTPS globally. This option can also be set on individual
|
93
|
+
# geocoder classes.
|
94
|
+
# Geokit::Geocoders::secure = false
|
95
|
+
|
96
|
+
# Control verification of the server certificate for geocoders using HTTPS
|
97
|
+
# Geokit::Geocoders::ssl_verify_mode = OpenSSL::SSL::VERIFY_(PEER/NONE)
|
98
|
+
# Setting this to VERIFY_NONE may be needed on systems that don't have
|
99
|
+
# a complete or up to date root certificate store. Only applies to
|
100
|
+
# the Net::HTTP adapter.
|
data/lib/geokit-rails.rb
CHANGED
@@ -11,6 +11,8 @@ module Geokit
|
|
11
11
|
extend ActiveSupport::Concern
|
12
12
|
|
13
13
|
module ClassMethods # :nodoc:
|
14
|
+
OPTION_SYMBOLS = [ :distance_column_name, :default_units, :default_formula, :lat_column_name, :lng_column_name, :qualified_lat_column_name, :qualified_lng_column_name, :skip_loading ]
|
15
|
+
|
14
16
|
def acts_as_mappable(options = {})
|
15
17
|
metaclass = (class << self; self; end)
|
16
18
|
|
@@ -21,20 +23,21 @@ module Geokit
|
|
21
23
|
|
22
24
|
if reflection = Geokit::ActsAsMappable.end_of_reflection_chain(self.through, self)
|
23
25
|
metaclass.instance_eval do
|
24
|
-
|
26
|
+
OPTION_SYMBOLS.each do |method_name|
|
25
27
|
define_method method_name do
|
26
28
|
reflection.klass.send(method_name)
|
27
29
|
end
|
28
30
|
end
|
29
31
|
end
|
30
32
|
else
|
31
|
-
cattr_accessor
|
33
|
+
cattr_accessor *OPTION_SYMBOLS
|
32
34
|
|
33
35
|
self.distance_column_name = options[:distance_column_name] || 'distance'
|
34
36
|
self.default_units = options[:default_units] || Geokit::default_units
|
35
37
|
self.default_formula = options[:default_formula] || Geokit::default_formula
|
36
38
|
self.lat_column_name = options[:lat_column_name] || 'lat'
|
37
39
|
self.lng_column_name = options[:lng_column_name] || 'lng'
|
40
|
+
self.skip_loading = options[:skip_loading]
|
38
41
|
self.qualified_lat_column_name = "#{table_name}.#{lat_column_name}"
|
39
42
|
self.qualified_lng_column_name = "#{table_name}.#{lng_column_name}"
|
40
43
|
|
@@ -91,11 +94,21 @@ module Geokit
|
|
91
94
|
module ClassMethods
|
92
95
|
|
93
96
|
# A proxy to an instance of a finder adapter, inferred from the connection's adapter.
|
94
|
-
def
|
95
|
-
@
|
96
|
-
|
97
|
+
def geokit_finder_adapter
|
98
|
+
@geokit_finder_adapter ||= begin
|
99
|
+
unless Adapters.const_defined?(connection.adapter_name.camelcase)
|
100
|
+
filename = connection.adapter_name.downcase
|
101
|
+
require File.join("geokit-rails", "adapters", filename)
|
102
|
+
end
|
97
103
|
klass = Adapters.const_get(connection.adapter_name.camelcase)
|
98
|
-
klass.
|
104
|
+
if klass.class == Module
|
105
|
+
# For some reason Mysql2 adapter was defined in Adapters.constants but was Module instead of a Class
|
106
|
+
filename = connection.adapter_name.downcase
|
107
|
+
require File.join("geokit-rails", "adapters", filename)
|
108
|
+
# Re-init the klass after require
|
109
|
+
klass = Adapters.const_get(connection.adapter_name.camelcase)
|
110
|
+
end
|
111
|
+
klass.load(self) unless klass.loaded || skip_loading
|
99
112
|
klass.new(self)
|
100
113
|
rescue LoadError
|
101
114
|
raise UnsupportedAdapter, "`#{connection.adapter_name.downcase}` is not a supported adapter."
|
@@ -104,8 +117,13 @@ module Geokit
|
|
104
117
|
|
105
118
|
def within(distance, options = {})
|
106
119
|
options[:within] = distance
|
107
|
-
#
|
108
|
-
|
120
|
+
# Add bounding box to speed up SQL request.
|
121
|
+
bounds = formulate_bounds_from_distance(
|
122
|
+
options,
|
123
|
+
normalize_point_to_lat_lng(options[:origin]),
|
124
|
+
options[:units] || default_units)
|
125
|
+
with_latlng.where(bound_conditions(bounds)).
|
126
|
+
where(distance_conditions(options))
|
109
127
|
end
|
110
128
|
alias inside within
|
111
129
|
|
@@ -123,30 +141,35 @@ module Geokit
|
|
123
141
|
end
|
124
142
|
|
125
143
|
def in_bounds(bounds, options = {})
|
144
|
+
inclusive = options.delete(:inclusive) || false
|
126
145
|
options[:bounds] = bounds
|
127
146
|
#geo_scope(options)
|
128
147
|
#where(distance_conditions(options))
|
129
148
|
bounds = extract_bounds_from_options(options)
|
130
|
-
where(bound_conditions(bounds))
|
149
|
+
where(bound_conditions(bounds, inclusive))
|
131
150
|
end
|
132
151
|
|
133
152
|
def by_distance(options = {})
|
134
153
|
origin = extract_origin_from_options(options)
|
135
154
|
units = extract_units_from_options(options)
|
136
155
|
formula = extract_formula_from_options(options)
|
137
|
-
bounds = extract_bounds_from_options(options)
|
138
156
|
distance_column_name = distance_sql(origin, units, formula)
|
139
|
-
|
140
|
-
|
157
|
+
with_latlng.order(
|
158
|
+
Arel.sql(distance_column_name).send(options[:reverse] ? 'desc' : 'asc')
|
159
|
+
)
|
160
|
+
end
|
161
|
+
|
162
|
+
def with_latlng
|
163
|
+
where("#{qualified_lat_column_name} IS NOT NULL AND #{qualified_lng_column_name} IS NOT NULL")
|
141
164
|
end
|
142
165
|
|
143
166
|
def closest(options = {})
|
144
|
-
by_distance(options).
|
167
|
+
by_distance(options).limit(1)
|
145
168
|
end
|
146
169
|
alias nearest closest
|
147
170
|
|
148
171
|
def farthest(options = {})
|
149
|
-
by_distance(options).
|
172
|
+
by_distance({:reverse => true}.merge(options)).limit(1)
|
150
173
|
end
|
151
174
|
|
152
175
|
#def geo_scope(options = {})
|
@@ -162,9 +185,9 @@ module Geokit
|
|
162
185
|
|
163
186
|
# if origin
|
164
187
|
# arel.distance_formula = distance_sql(origin, units, formula)
|
165
|
-
#
|
188
|
+
#
|
166
189
|
# if arel.select_values.blank?
|
167
|
-
# star_select = Arel::SqlLiteral.new(arel.quoted_table_name + '.*')
|
190
|
+
# star_select = Arel::Nodes::SqlLiteral.new(arel.quoted_table_name + '.*')
|
168
191
|
# arel = arel.select(star_select)
|
169
192
|
# end
|
170
193
|
# end
|
@@ -211,10 +234,10 @@ module Geokit
|
|
211
234
|
# If it's a :within query, add a bounding box to improve performance.
|
212
235
|
# This only gets called if a :bounds argument is not otherwise supplied.
|
213
236
|
def formulate_bounds_from_distance(options, origin, units)
|
214
|
-
distance = options[:within] if options.has_key?(:within)
|
237
|
+
distance = options[:within] if options.has_key?(:within) && options[:within].is_a?(Numeric)
|
215
238
|
distance = options[:range].last-(options[:range].exclude_end?? 1 : 0) if options.has_key?(:range)
|
216
239
|
if distance
|
217
|
-
|
240
|
+
Geokit::Bounds.from_point_and_radius(origin,distance,:units=>units)
|
218
241
|
else
|
219
242
|
nil
|
220
243
|
end
|
@@ -224,25 +247,41 @@ module Geokit
|
|
224
247
|
origin = extract_origin_from_options(options)
|
225
248
|
units = extract_units_from_options(options)
|
226
249
|
formula = extract_formula_from_options(options)
|
227
|
-
bounds = extract_bounds_from_options(options)
|
228
250
|
distance_column_name = distance_sql(origin, units, formula)
|
229
251
|
|
230
|
-
|
231
|
-
|
252
|
+
if options.has_key?(:within)
|
253
|
+
Arel.sql(distance_column_name).lteq(options[:within])
|
232
254
|
elsif options.has_key?(:beyond)
|
233
|
-
|
255
|
+
Arel.sql(distance_column_name).gt(options[:beyond])
|
234
256
|
elsif options.has_key?(:range)
|
235
|
-
|
257
|
+
min_condition = Arel.sql(distance_column_name).gteq(options[:range].begin)
|
258
|
+
max_condition = if options[:range].exclude_end?
|
259
|
+
Arel.sql(distance_column_name).lt(options[:range].end)
|
260
|
+
else
|
261
|
+
Arel.sql(distance_column_name).lteq(options[:range].end)
|
262
|
+
end
|
263
|
+
min_condition.and(max_condition)
|
236
264
|
end
|
237
|
-
Arel::SqlLiteral.new("(#{res})") if res.present?
|
238
265
|
end
|
239
266
|
|
240
|
-
def bound_conditions(bounds)
|
267
|
+
def bound_conditions(bounds, inclusive = false)
|
268
|
+
return nil unless bounds
|
269
|
+
if inclusive
|
270
|
+
lt_operator = :lteq
|
271
|
+
gt_operator = :gteq
|
272
|
+
else
|
273
|
+
lt_operator = :lt
|
274
|
+
gt_operator = :gt
|
275
|
+
end
|
241
276
|
sw,ne = bounds.sw, bounds.ne
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
277
|
+
lat, lng = Arel.sql(qualified_lat_column_name), Arel.sql(qualified_lng_column_name)
|
278
|
+
lat.send(gt_operator, sw.lat).and(lat.send(lt_operator, ne.lat)).and(
|
279
|
+
if bounds.crosses_meridian?
|
280
|
+
lng.send(lt_operator, ne.lng).or(lng.send(gt_operator, sw.lng))
|
281
|
+
else
|
282
|
+
lng.send(gt_operator, sw.lng).and(lng.send(lt_operator, ne.lng))
|
283
|
+
end
|
284
|
+
)
|
246
285
|
end
|
247
286
|
|
248
287
|
# Extracts the origin instance out of the options if it exists and returns
|
@@ -315,20 +354,31 @@ module Geokit
|
|
315
354
|
# Returns the distance SQL using the spherical world formula (Haversine). The SQL is tuned
|
316
355
|
# to the database in use.
|
317
356
|
def sphere_distance_sql(origin, units)
|
318
|
-
|
319
|
-
|
357
|
+
# "origin" can be a Geokit::LatLng (with :lat and :lng methods), e.g.
|
358
|
+
# when using geo_scope or it can be an ActsAsMappable with customized
|
359
|
+
# latitude and longitude methods, e.g. when using distance_sql.
|
360
|
+
lat = deg2rad(get_lat(origin))
|
361
|
+
lng = deg2rad(get_lng(origin))
|
320
362
|
multiplier = units_sphere_multiplier(units)
|
321
|
-
|
322
|
-
adapter.sphere_distance_sql(lat, lng, multiplier) if adapter
|
363
|
+
geokit_finder_adapter.sphere_distance_sql(lat, lng, multiplier) if geokit_finder_adapter
|
323
364
|
end
|
324
365
|
|
325
366
|
# Returns the distance SQL using the flat-world formula (Phythagorean Theory). The SQL is tuned
|
326
367
|
# to the database in use.
|
327
368
|
def flat_distance_sql(origin, units)
|
328
369
|
lat_degree_units = units_per_latitude_degree(units)
|
329
|
-
lng_degree_units = units_per_longitude_degree(origin
|
370
|
+
lng_degree_units = units_per_longitude_degree(get_lat(origin), units)
|
371
|
+
geokit_finder_adapter.flat_distance_sql(origin, lat_degree_units, lng_degree_units)
|
372
|
+
end
|
373
|
+
|
374
|
+
def get_lat(origin)
|
375
|
+
origin.respond_to?(:lat) ? origin.lat \
|
376
|
+
: origin.send(:"#{lat_column_name}")
|
377
|
+
end
|
330
378
|
|
331
|
-
|
379
|
+
def get_lng(origin)
|
380
|
+
origin.respond_to?(:lng) ? origin.lng \
|
381
|
+
: origin.send(:"#{lng_column_name}")
|
332
382
|
end
|
333
383
|
|
334
384
|
end # ClassMethods
|
@@ -339,8 +389,8 @@ module Geokit
|
|
339
389
|
geo=Geokit::Geocoders::MultiGeocoder.geocode(address)
|
340
390
|
|
341
391
|
if geo.success
|
342
|
-
self.send("#{lat_column_name}=", geo.
|
343
|
-
self.send("#{lng_column_name}=", geo.
|
392
|
+
self.send("#{lat_column_name}=", geo.send(:"#{lat_column_name}"))
|
393
|
+
self.send("#{lng_column_name}=", geo.send(:"#{lng_column_name}"))
|
344
394
|
else
|
345
395
|
errors.add(auto_geocode_field, auto_geocode_error_message)
|
346
396
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Geokit
|
2
|
+
module Adapters
|
3
|
+
class OracleEnhanced < Abstract
|
4
|
+
TO_DEGREES = Math::PI / 180
|
5
|
+
def sphere_distance_sql(lat, lng, multiplier)
|
6
|
+
%{
|
7
|
+
(
|
8
|
+
ACOS(
|
9
|
+
COS(#{lat}) * COS(#{lng}) *
|
10
|
+
COS(#{TO_DEGREES} * #{qualified_lat_column_name}) *
|
11
|
+
COS(#{TO_DEGREES} * #{qualified_lng_column_name}) +
|
12
|
+
COS(#{lat}) * SIN(#{lng}) *
|
13
|
+
COS(#{TO_DEGREES} * #{qualified_lat_column_name}) *
|
14
|
+
SIN(#{TO_DEGREES} * #{qualified_lng_column_name}) +
|
15
|
+
SIN(#{lat}) *
|
16
|
+
SIN(#{TO_DEGREES} * #{qualified_lat_column_name})
|
17
|
+
) *
|
18
|
+
#{multiplier})
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
def flat_distance_sql(origin, lat_degree_units, lng_degree_units)
|
23
|
+
%{
|
24
|
+
SQRT(
|
25
|
+
POWER(#{lat_degree_units}*(#{origin.lat}-#{qualified_lat_column_name}), 2)
|
26
|
+
POWER(#{lng_degree_units}*(#{origin.lng}-#{qualified_lng_column_name}), 2)
|
27
|
+
)
|
28
|
+
}
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|