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 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
- River.where(:source.near => [-73.98, 40.77])
72
- River.where(:source.near => [[-73.98, 40.77],5]) # sets max distance of 5
73
- River.where(:source.near => {:point => [-73.98, 40.77], :max => 5}) # sets max distance of 5
74
- River.where(:source.near(:sphere) => [[-73.98, 40.77],5]) # sets max distance of 5 radians
75
- River.where(:source.near(:sphere) => {:point => [-73.98, 40.77], :max => 5, :unit => :km}) # sets max distance of 5 km
76
- River.where(:source.near(:sphere) => [-73.98, 40.77])
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
- River.where(:source.within(:box) => [[-73.99756,40.73083], [-73.988135,40.741404]])
79
- River.where(:source.within(:box) => [ {:lat => 40.73083, :lng => -73.99756}, [-73.988135,40.741404]])
80
- River.where(:source.within(:polygon) => [ [ 10, 20 ], [ 10, 40 ], [ 30, 40 ], [ 30, 20 ] ]
81
- River.where(:source.within(:polygon) => { a : { x : 10, y : 20 }, b : { x : 15, y : 25 }, c : { x : 20, y : 20 } })
82
- River.where(:source.within(:center) => [[-73.98, 40.77],5]) # same format as near
83
- River.where(:source.within(:center_sphere) => [[-73.98, 40.77],5]) # same format as near(:sphere)
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
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
- query = create_geo_near_query(center,opts)
41
- results = klass.db.command(query)
42
- if results['results'].kind_of?(Array) && results['results'].size > 0
43
- rows = results['results'].collect do |result|
44
- res = Mongoid::Factory.from_db(klass, result.delete('obj'))
45
- res.geo = {}
46
- # camel case is awkward in ruby when using variables...
47
- if result['dis']
48
- res.geo[:distance] = result.delete('dis').to_f
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'] = (self.options[:skip] || 0) + opts[:num].to_i
99
- elsif self.options[:limit]
100
- query['num'] = (self.options[:skip] || 0) + self.options[:limit]
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[0]}
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[0]} if options[:class].blank?
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::Geo.lng_symbols.index(self.keys[1])
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::Geo.lat_symbols.index(self.keys[0])
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 = 0.017453293
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
- def haversine(p1,p2)
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
- dlon = lon2 - lon1
30
- dlat = lat2 - lat1
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
- lat1_rad = lat1 * RAD_PER_DEG
36
- lon1_rad = lon1 * RAD_PER_DEG
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
- lat2_rad = lat2 * RAD_PER_DEG
39
- lon2_rad = lon2 * RAD_PER_DEG
35
+ dlon = p2[0] - p1[0]
36
+ dlat = p2[1] - p1[1]
40
37
 
41
- a = (Math.sin(dlat_rad/2))**2 + Math.cos(lat1_rad) * Math.cos(lat2_rad) * (Math.sin(dlon_rad/2))**2
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
@@ -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.1"
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-22}
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/mongoid_spacial/criterion/complex_spec.rb",
120
- "spec/unit/mongoid_spacial/criterion/inclusion_spec.rb",
121
- "spec/unit/mongoid_spacial/criterion/near_spacial_spec.rb",
122
- "spec/unit/mongoid_spacial/criterion/within_spacial_spec.rb"
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
- before do
6
- Bar.delete_all
7
- Bar.create_indexes
8
- end
9
-
10
- let!(:munich) do
11
- Bar.create(:location => [45, 11], :name => 'Munich')
12
- end
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 = [-47,23.5]
20
- near = Bar.geo_near(location)
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 = [-47,23.5]
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 limit on maximum distance" do
34
- location = [45.1, 11.1]
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 :distanceMultiplier' do
39
+
40
+ describe 'option :distance_multiplier' do
42
41
  it "should multiply returned distance with multiplier" do
43
- location = [45.1, 11.1]
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
- location = [45.1, 11.1]
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
- location = [45.1, 11.1]
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 => 'Munich'}).size.should == 1
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 = [45.1, 11.1]
81
- # two record in the collection, only one's name is Munich
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 = [-47,23.5]
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 = [-47,23.5]
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
@@ -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.1
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-22 00:00:00 Z
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/mongoid_spacial/criterion/complex_spec.rb
246
- - spec/unit/mongoid_spacial/criterion/inclusion_spec.rb
247
- - spec/unit/mongoid_spacial/criterion/near_spacial_spec.rb
248
- - spec/unit/mongoid_spacial/criterion/within_spacial_spec.rb
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: -4261020674425124733
264
+ hash: -2362332534301507743
263
265
  segments:
264
266
  - 0
265
267
  version: "0"