mongoid_spacial 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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"