mongoid_spacial 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +15 -12
- data/VERSION +1 -1
- data/lib/mongoid_spacial/contexts/mongo.rb +27 -53
- data/lib/mongoid_spacial/field_option.rb +2 -2
- data/lib/mongoid_spacial/spacial/core_ext.rb +2 -2
- data/lib/mongoid_spacial/spacial/formulas.rb +14 -17
- data/lib/mongoid_spacial/spacial/geo_near.rb +84 -0
- data/lib/mongoid_spacial/spacial.rb +7 -3
- data/mongoid_spacial.gemspec +8 -6
- data/spec/functional/mongoid/contexts/mongo_spec.rb +34 -53
- data/spec/unit/{mongoid_spacial → mongoid}/criterion/complex_spec.rb +0 -0
- data/spec/unit/{mongoid_spacial → mongoid}/criterion/inclusion_spec.rb +0 -0
- data/spec/unit/{mongoid_spacial → mongoid}/criterion/near_spacial_spec.rb +0 -0
- data/spec/unit/{mongoid_spacial → mongoid}/criterion/within_spacial_spec.rb +0 -0
- data/spec/unit/mongoid/spacial/formulas_spec.rb +37 -0
- metadata +9 -7
data/README.md
CHANGED
@@ -37,7 +37,9 @@ end
|
|
37
37
|
```
|
38
38
|
|
39
39
|
Before we manipulate the data mongoid_spacial handles is what we call points.
|
40
|
+
|
40
41
|
Points can be:
|
42
|
+
|
41
43
|
* an unordered hash with the lat long string keys defined when setting the field (only applies for setting the field)
|
42
44
|
* longitude latitude array in that order - [long,lat]
|
43
45
|
* an unordered hash with latitude key(:lat, :latitude) and a longitude key(:lon, :long, :lng, :longitude)
|
@@ -67,20 +69,21 @@ hudson.mouth #=> [-74.026667, 40.703056] # notice how this returned as a lng,la
|
|
67
69
|
# notice how the order of lng and lat were switched. it will always come out like this when using spacial.
|
68
70
|
```
|
69
71
|
Mongoid Geo has extended all built in spacial symbol extentions
|
72
|
+
|
70
73
|
* near
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
74
|
+
* River.where(:source.near => [-73.98, 40.77])
|
75
|
+
* River.where(:source.near => [[-73.98, 40.77],5]) # sets max distance of 5
|
76
|
+
* River.where(:source.near => {:point => [-73.98, 40.77], :max => 5}) # sets max distance of 5
|
77
|
+
* River.where(:source.near(:sphere) => [[-73.98, 40.77],5]) # sets max distance of 5 radians
|
78
|
+
* River.where(:source.near(:sphere) => {:point => [-73.98, 40.77], :max => 5, :unit => :km}) # sets max distance of 5 km
|
79
|
+
* River.where(:source.near(:sphere) => [-73.98, 40.77])
|
77
80
|
* within
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
81
|
+
* River.where(:source.within(:box) => [[-73.99756,40.73083], [-73.988135,40.741404]])
|
82
|
+
* River.where(:source.within(:box) => [ {:lat => 40.73083, :lng => -73.99756}, [-73.988135,40.741404]])
|
83
|
+
* River.where(:source.within(:polygon) => [ [ 10, 20 ], [ 10, 40 ], [ 30, 40 ], [ 30, 20 ] ]
|
84
|
+
* River.where(:source.within(:polygon) => { a : { x : 10, y : 20 }, b : { x : 15, y : 25 }, c : { x : 20, y : 20 } })
|
85
|
+
* River.where(:source.within(:center) => [[-73.98, 40.77],5]) # same format as near
|
86
|
+
* River.where(:source.within(:center_sphere) => [[-73.98, 40.77],5]) # same format as near(:sphere)
|
84
87
|
|
85
88
|
One of the most handy features we have added is geo_near finder
|
86
89
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0
|
1
|
+
0.1.0
|
@@ -2,21 +2,21 @@
|
|
2
2
|
module Mongoid #:nodoc:
|
3
3
|
module Contexts #:nodoc:
|
4
4
|
class Mongo #:nodoc:
|
5
|
-
|
5
|
+
|
6
6
|
# Fetches rows from the data base sorted by distance.
|
7
7
|
# In MongoDB versions 1.7 and above it returns a distance.
|
8
8
|
# Uses all criteria chains except without, only, asc, desc, order_by
|
9
9
|
#
|
10
10
|
# @example Minimal Query
|
11
|
-
#
|
11
|
+
#
|
12
12
|
# Address.geo_near([70,40])
|
13
13
|
#
|
14
14
|
# @example Chained Query
|
15
|
-
#
|
15
|
+
#
|
16
16
|
# Address.where(:state => 'ny').geo_near([70,40])
|
17
17
|
#
|
18
18
|
# @example Calc Distances Query
|
19
|
-
#
|
19
|
+
#
|
20
20
|
# Address.geo_near([70,40], :max_distance => 5, :unit => 5)
|
21
21
|
#
|
22
22
|
# @param [ Array, Hash, #to_lng_lat ] center The center of where to calculate distance from
|
@@ -31,57 +31,29 @@ module Mongoid #:nodoc:
|
|
31
31
|
#
|
32
32
|
# @return [ Array ] Sorted Rows
|
33
33
|
def geo_near(center, opts = {})
|
34
|
+
opts = self.options.merge(opts)
|
35
|
+
# convert point
|
34
36
|
center = center.to_lng_lat if center.respond_to?(:to_lng_lat)
|
35
37
|
|
38
|
+
# set default opts
|
36
39
|
if distance_multiplier = Mongoid::Spacial.earth_radius[opts.delete(:unit)]
|
37
40
|
opts[:distance_multiplier] = distance_multiplier
|
38
41
|
end
|
39
42
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
end
|
50
|
-
result.each do |key,value|
|
51
|
-
res.geo[key.snakecase.to_sym] = value
|
43
|
+
if opts.has_key?(:page)
|
44
|
+
opts[:page] ||= 1
|
45
|
+
opts[:paginator] ||= Mongoid::Spacial.paginator
|
46
|
+
if opts[:paginator] == :will_paginate
|
47
|
+
opts[:per_page] ||= klass.per_page
|
48
|
+
elsif opts[:paginator] == :kaminari
|
49
|
+
opts[:per_page] ||= Kaminari.config.default_per_page
|
50
|
+
else
|
51
|
+
opts[:per_page] ||= 25
|
52
52
|
end
|
53
|
-
# dist_options[:formula] = opts[:formula] if opts[:formula]
|
54
|
-
opts[:calculate] = klass.spacial_fields_indexed if klass.spacial_fields_indexed.kind_of?(Array) && opts[:calculate] == true
|
55
|
-
if opts[:calculate]
|
56
|
-
opts[:calculate] = [opts[:calculate]] unless opts[:calculate].kind_of? Array
|
57
|
-
opts[:calculate] = opts[:calculate].map(&:to_sym) & geo_fields
|
58
|
-
if klass.spacial_fields_indexed.kind_of?(Array) && klass.spacial_fields_indexed.size == 1
|
59
|
-
primary = klass.spacial_fields_indexed.first
|
60
|
-
end
|
61
|
-
opts[:calculate].each do |key|
|
62
|
-
key = (key.to_s+'_distance').to_s
|
63
|
-
res.geo[key] = res.distance_from(key,center, opts[:distance_multiplier])
|
64
|
-
res.geo[:distance] = res.geo[key] if primary && key == primary
|
65
|
-
end
|
66
|
-
end
|
67
|
-
res
|
68
|
-
end
|
69
|
-
else
|
70
|
-
rows = []
|
71
|
-
end
|
72
|
-
# if opts.has_key?(:page) || opts[:paginator]
|
73
|
-
# opts[:paginator] ||= Mongoid::Spacial::Config.paginator
|
74
|
-
# if opts[:paginator] == :kaminari
|
75
|
-
|
76
|
-
# elsif opts[:paginator] == :will_paginate
|
77
|
-
# end
|
78
|
-
# end
|
79
|
-
|
80
|
-
if self.options[:skip] && rows.size > self.options[:skip]
|
81
|
-
rows[self.options[:skip]..rows.size-1]
|
82
|
-
else
|
83
|
-
rows
|
84
53
|
end
|
54
|
+
query = create_geo_near_query(center,opts)
|
55
|
+
results = klass.db.command(query)
|
56
|
+
Mongoid::Spacial::GeoNear.new(klass,results,opts)
|
85
57
|
end
|
86
58
|
|
87
59
|
private
|
@@ -90,14 +62,16 @@ module Mongoid #:nodoc:
|
|
90
62
|
# minimum query
|
91
63
|
query = {
|
92
64
|
:geoNear => klass.to_s.tableize,
|
93
|
-
:near => center,
|
65
|
+
:near => center,
|
94
66
|
}
|
95
67
|
|
96
68
|
# create limit and use skip
|
97
|
-
if opts[:num]
|
98
|
-
query['num'] = (
|
99
|
-
elsif
|
100
|
-
query['num'] = (
|
69
|
+
if opts[:num]
|
70
|
+
query['num'] = (opts[:skip] || 0) + opts[:num].to_i
|
71
|
+
elsif opts[:limit]
|
72
|
+
query['num'] = (opts[:skip] || 0) + opts[:limit]
|
73
|
+
elsif opts[:page]
|
74
|
+
query['num'] = (opts[:page] * opts[:per_page])
|
101
75
|
end
|
102
76
|
|
103
77
|
# allow the use of complex werieis
|
@@ -112,7 +86,7 @@ module Mongoid #:nodoc:
|
|
112
86
|
query['maxDistance'] = query['maxDistance']/opts[:distance_multiplier] if opts[:distance_multiplier]
|
113
87
|
end
|
114
88
|
|
115
|
-
if klass.db.connection.server_version >= '1.7'
|
89
|
+
if klass.db.connection.server_version >= '1.7'
|
116
90
|
query['spherical'] = true if opts[:spherical]
|
117
91
|
|
118
92
|
# mongodb < 1.7 returns degrees but with earth flat. in Mongodb 1.7 you can set sphere and let mongodb calculate the distance in Miles or KM
|
@@ -16,7 +16,7 @@ field.option :spacial do |model,field,options|
|
|
16
16
|
|
17
17
|
define_method field.name do
|
18
18
|
output = self[field.name] || [nil,nil]
|
19
|
-
output = (options[:return_array]) ? lng_lat_a : {lng_meth => output[0], lat_meth => output[
|
19
|
+
output = (options[:return_array]) ? lng_lat_a : {lng_meth => output[0], lat_meth => output[1]}
|
20
20
|
return options[:class].new(output) if options[:class]
|
21
21
|
output
|
22
22
|
end
|
@@ -29,7 +29,7 @@ field.option :spacial do |model,field,options|
|
|
29
29
|
end
|
30
30
|
self[field.name]=arg
|
31
31
|
return arg[0..1] if options[:return_array]
|
32
|
-
return h = {lng_meth => arg[0], lat_meth => arg[
|
32
|
+
return h = {lng_meth => arg[0], lat_meth => arg[1]} if options[:class].blank?
|
33
33
|
options[:class].new(h)
|
34
34
|
end
|
35
35
|
end
|
@@ -14,14 +14,14 @@ class Hash
|
|
14
14
|
v = (Mongoid::Spacial.lat_symbols & self.keys).first
|
15
15
|
return self[v] if !v.nil? && self[v]
|
16
16
|
raise "Hash must contain #{Mongoid::Spacial.lat_symbols.inspect} if ruby version is less than 1.9" if RUBY_VERSION.to_f < 1.9
|
17
|
-
raise "Hash cannot contain #{Mongoid::Spacial.lng_symbols.inspect} as the second item if there is no #{Mongoid::Spacial.lat_symbols.inspect}" if Mongoid::
|
17
|
+
raise "Hash cannot contain #{Mongoid::Spacial.lng_symbols.inspect} as the second item if there is no #{Mongoid::Spacial.lat_symbols.inspect}" if Mongoid::Spacial.lng_symbols.index(self.keys[1])
|
18
18
|
self.values[1]
|
19
19
|
end
|
20
20
|
|
21
21
|
def to_lng
|
22
22
|
v = (Mongoid::Spacial.lng_symbols & self.keys).first
|
23
23
|
return self[v] if !v.nil? && self[v]
|
24
|
-
raise "Hash cannot contain #{Mongoid::Spacial.lat_symbols.inspect} as the first item if there is no #{Mongoid::Spacial.lng_symbols.inspect}" if Mongoid::
|
24
|
+
raise "Hash cannot contain #{Mongoid::Spacial.lat_symbols.inspect} as the first item if there is no #{Mongoid::Spacial.lng_symbols.inspect}" if Mongoid::Spacial.lat_symbols.index(self.keys[0])
|
25
25
|
self.values[0]
|
26
26
|
end
|
27
27
|
end
|
@@ -1,9 +1,12 @@
|
|
1
1
|
module Mongoid
|
2
2
|
module Spacial
|
3
3
|
module Formulas
|
4
|
-
RAD_PER_DEG =
|
4
|
+
RAD_PER_DEG = Math::PI/180
|
5
|
+
|
6
|
+
def self.n_vector(point1,point2)
|
7
|
+
p1 = point1.map{|deg| deg * RAD_PER_DEG}
|
8
|
+
p2 = point2.map{|deg| deg * RAD_PER_DEG}
|
5
9
|
|
6
|
-
def n_vector(p1,p2)
|
7
10
|
sin_x1 = Math.sin(p1[0])
|
8
11
|
cos_x1 = Math.cos(p1[0])
|
9
12
|
|
@@ -19,26 +22,20 @@ module Mongoid
|
|
19
22
|
cross_prod = (cos_y1*cos_x1 * cos_y2*cos_x2) +
|
20
23
|
(cos_y1*sin_x1 * cos_y2*sin_x2) +
|
21
24
|
(sin_y1 * sin_y2)
|
22
|
-
Math.acos(cross_prod)
|
23
|
-
end
|
24
25
|
|
25
|
-
|
26
|
-
lon1,lat1=p1
|
27
|
-
lon2,lat2=p2
|
26
|
+
return cross_prod > 0 ? 0 : Math::PI if (cross_prod >= 1 || cross_prod <= -1)
|
28
27
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
dlon_rad = dlon * RAD_PER_DEG
|
33
|
-
dlat_rad = dlat * RAD_PER_DEG
|
28
|
+
Math.acos(cross_prod)
|
29
|
+
end
|
34
30
|
|
35
|
-
|
36
|
-
|
31
|
+
def self.haversine(point1,point2)
|
32
|
+
p1 = point1.map{|deg| deg * RAD_PER_DEG}
|
33
|
+
p2 = point2.map{|deg| deg * RAD_PER_DEG}
|
37
34
|
|
38
|
-
|
39
|
-
|
35
|
+
dlon = p2[0] - p1[0]
|
36
|
+
dlat = p2[1] - p1[1]
|
40
37
|
|
41
|
-
a = (Math.sin(
|
38
|
+
a = (Math.sin(dlat/2))**2 + Math.cos(p1[1]) * Math.cos(p2[1]) * (Math.sin(dlon/2))**2
|
42
39
|
|
43
40
|
2 * Math.atan2( Math.sqrt(a), Math.sqrt(1-a))
|
44
41
|
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module Mongoid
|
2
|
+
module Spacial
|
3
|
+
class GeoNear < Array
|
4
|
+
attr_reader :stats
|
5
|
+
|
6
|
+
def initialize(klass,results,opts = {})
|
7
|
+
raise "class must include Mongoid::Spacial::Document" unless klass.respond_to?(:spacial_fields_indexed)
|
8
|
+
@klass, @stats,@opts = klass,results['stats'],opts
|
9
|
+
|
10
|
+
@_original_array = results['results'].collect do |result|
|
11
|
+
res = Mongoid::Factory.from_db(klass, result.delete('obj'))
|
12
|
+
res.geo = {}
|
13
|
+
# camel case is awkward in ruby when using variables...
|
14
|
+
if result['dis']
|
15
|
+
res.geo[:distance] = result.delete('dis').to_f
|
16
|
+
end
|
17
|
+
result.each do |key,value|
|
18
|
+
res.geo[key.snakecase.to_sym] = value
|
19
|
+
end
|
20
|
+
# dist_options[:formula] = opts[:formula] if opts[:formula]
|
21
|
+
opts[:calculate] = klass.spacial_fields_indexed if klass.spacial_fields_indexed.kind_of?(Array) && opts[:calculate] == true
|
22
|
+
if opts[:calculate]
|
23
|
+
opts[:calculate] = [opts[:calculate]] unless opts[:calculate].kind_of? Array
|
24
|
+
opts[:calculate] = opts[:calculate].map(&:to_sym) & geo_fields
|
25
|
+
if klass.spacial_fields_indexed.kind_of?(Array) && klass.spacial_fields_indexed.size == 1
|
26
|
+
primary = klass.spacial_fields_indexed.first
|
27
|
+
end
|
28
|
+
opts[:calculate].each do |key|
|
29
|
+
key = (key.to_s+'_distance').to_sym
|
30
|
+
res.geo[key] = res.distance_from(key,center, opts[:distance_multiplier])
|
31
|
+
res.geo[:distance] = res.geo[key] if primary && key == primary
|
32
|
+
end
|
33
|
+
end
|
34
|
+
res
|
35
|
+
end
|
36
|
+
|
37
|
+
if opts[:page]
|
38
|
+
start = (opts[:page]-1)*opts[:per_page] # assuming current_page is 1 based.
|
39
|
+
super(@_original_array[start, opts[:per_page]])
|
40
|
+
elsif opts[:skip] && @_original_array.size > opts[:skip]
|
41
|
+
super(@_original_array[opts[:skip]..-1])
|
42
|
+
else
|
43
|
+
super(@_original_array)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def current_page
|
48
|
+
@opts[:page]
|
49
|
+
end
|
50
|
+
|
51
|
+
def num_pages
|
52
|
+
@stats['nscanned']/@opts[:per_page]
|
53
|
+
end
|
54
|
+
alias_method :total_pages, :num_pages
|
55
|
+
|
56
|
+
def out_of_bounds?
|
57
|
+
current_page > total_pages
|
58
|
+
end
|
59
|
+
|
60
|
+
def limit_value
|
61
|
+
@opts[:per_page]
|
62
|
+
end
|
63
|
+
alias_method :per_page, :limit_value
|
64
|
+
|
65
|
+
def offset
|
66
|
+
(current_page - 1) * per_page
|
67
|
+
end
|
68
|
+
|
69
|
+
# current_page - 1 or nil if there is no previous page
|
70
|
+
def previous_page
|
71
|
+
current_page > 1 ? (current_page - 1) : nil
|
72
|
+
end
|
73
|
+
|
74
|
+
# current_page + 1 or nil if there is no next page
|
75
|
+
def next_page
|
76
|
+
current_page < total_pages ? (current_page + 1) : nil
|
77
|
+
end
|
78
|
+
|
79
|
+
def total_entries
|
80
|
+
@stats['nscanned']
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -1,9 +1,10 @@
|
|
1
1
|
require 'mongoid_spacial/spacial/core_ext'
|
2
|
+
require 'mongoid_spacial/spacial/formulas'
|
2
3
|
module Mongoid
|
3
4
|
module Spacial
|
4
|
-
autoload :Formulas, 'mongoid_spacial/spacial/formulas'
|
5
5
|
autoload :Document, 'mongoid_spacial/spacial/document'
|
6
|
-
|
6
|
+
autoload :GeoNear, 'mongoid_spacial/spacial/geo_near'
|
7
|
+
|
7
8
|
EARTH_RADIUS_KM = 6371 # taken directly from mongodb
|
8
9
|
|
9
10
|
EARTH_RADIUS = {
|
@@ -12,7 +13,7 @@ module Mongoid
|
|
12
13
|
:mi => EARTH_RADIUS_KM*0.621371192, # taken directly from mongodb
|
13
14
|
:ft => EARTH_RADIUS_KM*5280*0.621371192,
|
14
15
|
}
|
15
|
-
|
16
|
+
|
16
17
|
LNG_SYMBOLS = [:x, :lon, :long, :lng, :longitude]
|
17
18
|
LAT_SYMBOLS = [:y, :lat, :latitude]
|
18
19
|
|
@@ -33,5 +34,8 @@ module Mongoid
|
|
33
34
|
|
34
35
|
mattr_accessor :distance_formula
|
35
36
|
@@distance_formula = :n_vector
|
37
|
+
|
38
|
+
mattr_accessor :paginator
|
39
|
+
@@paginator = :kaminari
|
36
40
|
end
|
37
41
|
end
|
data/mongoid_spacial.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{mongoid_spacial}
|
8
|
-
s.version = "0.0
|
8
|
+
s.version = "0.1.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = [%q{Ryan Ong}]
|
12
|
-
s.date = %q{2011-06-
|
12
|
+
s.date = %q{2011-06-23}
|
13
13
|
s.description = %q{A Mongoid Extention that simplifies and adds support for MongoDB Geo Spacial Calculations.}
|
14
14
|
s.email = %q{ryanong@gmail.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -40,6 +40,7 @@ Gem::Specification.new do |s|
|
|
40
40
|
"lib/mongoid_spacial/spacial/core_ext.rb",
|
41
41
|
"lib/mongoid_spacial/spacial/document.rb",
|
42
42
|
"lib/mongoid_spacial/spacial/formulas.rb",
|
43
|
+
"lib/mongoid_spacial/spacial/geo_near.rb",
|
43
44
|
"mongoid_spacial.gemspec",
|
44
45
|
"spec/config/mongod.conf",
|
45
46
|
"spec/config/mongoid.yml",
|
@@ -116,10 +117,11 @@ Gem::Specification.new do |s|
|
|
116
117
|
"spec/models/wiki_page.rb",
|
117
118
|
"spec/spec_helper.rb",
|
118
119
|
"spec/support/authentication.rb",
|
119
|
-
"spec/unit/
|
120
|
-
"spec/unit/
|
121
|
-
"spec/unit/
|
122
|
-
"spec/unit/
|
120
|
+
"spec/unit/mongoid/criterion/complex_spec.rb",
|
121
|
+
"spec/unit/mongoid/criterion/inclusion_spec.rb",
|
122
|
+
"spec/unit/mongoid/criterion/near_spacial_spec.rb",
|
123
|
+
"spec/unit/mongoid/criterion/within_spacial_spec.rb",
|
124
|
+
"spec/unit/mongoid/spacial/formulas_spec.rb"
|
123
125
|
]
|
124
126
|
s.homepage = %q{http://github.com/ryanong/mongoid_spacial}
|
125
127
|
s.licenses = [%q{MIT}]
|
@@ -1,97 +1,78 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
3
|
describe Mongoid::Contexts::Mongo do
|
4
|
+
describe "#geo_near" do
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
6
|
+
before do
|
7
|
+
Bar.delete_all
|
8
|
+
Bar.create_indexes
|
9
|
+
end
|
10
|
+
|
11
|
+
let!(:jfk) do
|
12
|
+
Bar.create(:name => 'jfk', :location => [-73.77694444, 40.63861111 ])
|
13
|
+
end
|
14
|
+
|
15
|
+
let!(:lax) do
|
16
|
+
Bar.create(:name => 'lax', :location => [-118.40, 33.94])
|
17
|
+
end
|
13
18
|
|
14
|
-
let!(:berlin) do
|
15
|
-
Bar.create(:location => [46, 12], :name => 'Berlin')
|
16
|
-
end
|
17
|
-
describe "geo_near" do
|
18
19
|
it "should work with specifying specific center and different location attribute on collction" do
|
19
|
-
location
|
20
|
-
|
21
|
-
near.should == [munich,berlin]
|
22
|
-
near.first.geo[:distance].should > 0
|
20
|
+
Bar.geo_near(lax.location, :spherical => true).should == [lax, jfk]
|
21
|
+
Bar.geo_near(jfk.location, :spherical => true).should == [jfk, lax]
|
23
22
|
end
|
24
23
|
|
25
24
|
describe 'option :num' do
|
26
25
|
it "should limit number of results to 1" do
|
27
|
-
location
|
28
|
-
Bar.geo_near(location, :num => 1).size.should == 1
|
26
|
+
Bar.geo_near(jfk.location, :num => 1).size.should == 1
|
29
27
|
end
|
30
28
|
end
|
31
|
-
|
29
|
+
|
32
30
|
describe 'option :maxDistance' do
|
33
|
-
it "should
|
34
|
-
location
|
35
|
-
# db.runCommand({ geo_near : "points", near :[45.1, 11.1]}).results;
|
36
|
-
# dis: is 0.14141869255648362 and 1.2727947855285668
|
37
|
-
Bar.geo_near(location, :max_distance => 0.2).should == [munich]
|
31
|
+
it "should get 1 item" do
|
32
|
+
Bar.geo_near(lax.location, :spherical => true, :max_distance => 2465/Mongoid::Spacial.earth_radius[:mi]).size.should == 1
|
38
33
|
end
|
34
|
+
it "should get 2 items" do
|
35
|
+
Bar.geo_near(lax.location, :spherical => true, :max_distance => 2480/Mongoid::Spacial.earth_radius[:mi]).size.should == 2
|
36
|
+
end
|
37
|
+
|
39
38
|
end
|
40
|
-
|
41
|
-
describe 'option :
|
39
|
+
|
40
|
+
describe 'option :distance_multiplier' do
|
42
41
|
it "should multiply returned distance with multiplier" do
|
43
|
-
|
44
|
-
Bar.geo_near(location, :distance_multiplier => 4).first.geo[:distance].should > 0
|
42
|
+
Bar.geo_near(lax.location, :spherical => true, :distance_multiplier=> Mongoid::Spacial.earth_radius[:mi]).second.geo[:distance].to_i.should be_within(1).of(2469)
|
45
43
|
end
|
46
44
|
end
|
47
|
-
|
45
|
+
|
48
46
|
describe 'option :unit' do
|
49
47
|
it "should multiply returned distance with multiplier" do
|
50
|
-
|
51
|
-
distance = Bar.geo_near(location, :unit => :mi).first.geo[:distance]
|
52
|
-
distance.should > 559
|
53
|
-
distance.should < 560
|
48
|
+
Bar.geo_near(lax.location, :spherical => true, :unit => :mi).second.geo[:distance].to_i.should be_within(1).of(2469)
|
54
49
|
end
|
55
50
|
|
56
51
|
it "should convert max_distance to radians with unit" do
|
57
|
-
|
58
|
-
near = Bar.geo_near(location, :max_distance => 570, :unit => :mi)
|
59
|
-
near.size.should == 1
|
60
|
-
near.first.should == munich
|
61
|
-
end
|
62
|
-
|
63
|
-
it "should convert max_distance to radians with unit" do
|
64
|
-
location = [45.1, 11.1]
|
65
|
-
Bar.geo_near(location, :max_distance => 570, :distance_multiplier => 4, :unit => :mi).first.should == munich
|
52
|
+
Bar.geo_near(lax.location, :spherical => true, :max_distance => 2465, :unit => :mi).size.should == 1
|
66
53
|
end
|
67
54
|
|
68
55
|
end
|
69
56
|
|
70
57
|
describe 'option :query' do
|
71
58
|
it "should filter using extra query option" do
|
72
|
-
location = [45.1, 11.1]
|
73
59
|
# two record in the collection, only one's name is Munich
|
74
|
-
Bar.geo_near(location, :query => {:name =>
|
60
|
+
Bar.geo_near(jfk.location, :query => {:name => jfk.name}).should == [jfk]
|
75
61
|
end
|
76
62
|
end
|
77
63
|
|
78
64
|
describe 'criteria chaining' do
|
79
65
|
it "should filter by where" do
|
80
|
-
location
|
81
|
-
|
82
|
-
a = Bar.where(:name => 'Munich')
|
83
|
-
# p a.selector
|
84
|
-
# a.geo_near(location).size.should == 1
|
66
|
+
Bar.where(:name => jfk.name).geo_near(jfk.location).should == [jfk]
|
67
|
+
Bar.any_of({:name => jfk.name},{:name => lax.name}).geo_near(jfk.location).should == [jfk,lax]
|
85
68
|
end
|
86
69
|
|
87
70
|
it 'should skip 1' do
|
88
|
-
location
|
89
|
-
Bar.skip(1).geo_near(location).size.should == 1
|
71
|
+
Bar.skip(1).geo_near(jfk.location).size.should == 1
|
90
72
|
end
|
91
73
|
|
92
74
|
it 'should limit 1' do
|
93
|
-
location
|
94
|
-
Bar.limit(1).geo_near(location).size.should == 1
|
75
|
+
Bar.limit(1).geo_near(jfk.location).size.should == 1
|
95
76
|
end
|
96
77
|
|
97
78
|
end
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Mongoid::Spacial::Formulas do
|
4
|
+
context "#n_vector" do
|
5
|
+
it {
|
6
|
+
bna = [-86.67, 36.12]
|
7
|
+
lax = [-118.40, 33.94]
|
8
|
+
dist1 = Mongoid::Spacial::Formulas.n_vector(bna, lax)
|
9
|
+
dist2 = Mongoid::Spacial::Formulas.n_vector(lax, bna)
|
10
|
+
|
11
|
+
# target is 0.45306
|
12
|
+
dist1.should be_within(0.00001).of(0.45306)
|
13
|
+
dist2.should be_within(0.00001).of(0.45306)
|
14
|
+
}
|
15
|
+
it {
|
16
|
+
# actual distance 2471.788
|
17
|
+
jfk = [-73.77694444, 40.63861111 ]
|
18
|
+
lax = [-118.40, 33.94]
|
19
|
+
|
20
|
+
dist = Mongoid::Spacial::Formulas.n_vector(jfk, lax) * Mongoid::Spacial.earth_radius[:mi]
|
21
|
+
dist.should be_within(1).of(2469)
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
context "#haversine" do
|
26
|
+
it {
|
27
|
+
# actual distance 2471.788
|
28
|
+
jfk = [-73.77694444, 40.63861111 ]
|
29
|
+
lax = [-118.40, 33.94]
|
30
|
+
|
31
|
+
dist = Mongoid::Spacial::Formulas.haversine(jfk, lax) * Mongoid::Spacial.earth_radius[:mi]
|
32
|
+
dist.should be_within(1).of(2469)
|
33
|
+
}
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: mongoid_spacial
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.0
|
5
|
+
version: 0.1.0
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Ryan Ong
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-06-
|
13
|
+
date: 2011-06-23 00:00:00 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: mongoid
|
@@ -166,6 +166,7 @@ files:
|
|
166
166
|
- lib/mongoid_spacial/spacial/core_ext.rb
|
167
167
|
- lib/mongoid_spacial/spacial/document.rb
|
168
168
|
- lib/mongoid_spacial/spacial/formulas.rb
|
169
|
+
- lib/mongoid_spacial/spacial/geo_near.rb
|
169
170
|
- mongoid_spacial.gemspec
|
170
171
|
- spec/config/mongod.conf
|
171
172
|
- spec/config/mongoid.yml
|
@@ -242,10 +243,11 @@ files:
|
|
242
243
|
- spec/models/wiki_page.rb
|
243
244
|
- spec/spec_helper.rb
|
244
245
|
- spec/support/authentication.rb
|
245
|
-
- spec/unit/
|
246
|
-
- spec/unit/
|
247
|
-
- spec/unit/
|
248
|
-
- spec/unit/
|
246
|
+
- spec/unit/mongoid/criterion/complex_spec.rb
|
247
|
+
- spec/unit/mongoid/criterion/inclusion_spec.rb
|
248
|
+
- spec/unit/mongoid/criterion/near_spacial_spec.rb
|
249
|
+
- spec/unit/mongoid/criterion/within_spacial_spec.rb
|
250
|
+
- spec/unit/mongoid/spacial/formulas_spec.rb
|
249
251
|
homepage: http://github.com/ryanong/mongoid_spacial
|
250
252
|
licenses:
|
251
253
|
- MIT
|
@@ -259,7 +261,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
259
261
|
requirements:
|
260
262
|
- - ">="
|
261
263
|
- !ruby/object:Gem::Version
|
262
|
-
hash: -
|
264
|
+
hash: -2362332534301507743
|
263
265
|
segments:
|
264
266
|
- 0
|
265
267
|
version: "0"
|