mongoid_geospatial 2.3.0 → 2.5.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
@@ -3,7 +3,6 @@ Mongoid Geospatial
3
3
 
4
4
  A Mongoid Extension that simplifies the use of MongoDB spatial features.
5
5
 
6
-
7
6
  ** On beta again **
8
7
 
9
8
  Removing some trash, improving and adding support for RGeo and GeoRuby.
@@ -25,98 +24,26 @@ You can also use an external Geometric/Spatial alongside.
25
24
  # Gemfile
26
25
  gem 'mongoid_geospatial'
27
26
 
28
-
29
27
  # A place to illustrate Point, Line and Polygon
30
28
  class Place
31
29
  include Mongoid::Document
30
+
31
+ # Include the module
32
32
  include Mongoid::Geospatial
33
33
 
34
+ # Just like mongoid,
34
35
  field :name, type: String
36
+ # define your field, but choose a geometry type:
35
37
  field :location, type: Point, :spatial => true
36
38
  field :route, type: Linestring
37
39
  field :area, type: Polygon
40
+
41
+ # If your are going to query on your points, don't forget to index:
42
+ spatial_index :location
43
+
38
44
  end
39
45
 
40
46
 
41
- Geometry Helpers
42
- ----------------
43
-
44
- We currently support GeoRuby and RGeo.
45
- If you require one of those, a #to_geo method will be available to all
46
- spatial fields, returning the external library corresponding object.
47
- To illustrate:
48
-
49
- class Person
50
- include Mongoid::Document
51
- include Mongoid::Geospatial
52
-
53
- field :location, type: Point
54
- end
55
-
56
- me = Person.new(location: [8, 8])
57
-
58
- # Example with GeoRuby
59
- point.class # Mongoid::Geospatial::Point
60
- point.to_geo.class # GeoRuby::SimpleFeatures::Point
61
-
62
- # Example with RGeo
63
- point.class # Mongoid::Geospatial::Point
64
- point.to_geo.class # RGeo::Geographic::SphericalPointImpl
65
-
66
-
67
- Configure
68
- ----------------
69
-
70
- Assemble it as you need (use a initializer file):
71
-
72
- With RGeo
73
-
74
- Mongoid::Geospatial.use_rgeo
75
- # Optional
76
- # Mongoid::Geospatial.factory = RGeo::Geographic.spherical_factory
77
-
78
- With GeoRuby
79
-
80
- Mongoid::Geospatial.use_georuby
81
-
82
- Defaults (change if you know what you're doing)
83
-
84
- Mongoid::Geospatial.lng_symbol = :x
85
- Mongoid::Geospatial.lat_symbol = :y
86
- Mongoid::Geospatial.earth_radius = EARTH_RADIUS
87
-
88
-
89
-
90
- Model Setup
91
- -----------
92
-
93
- You can create Point, Line, Circle, Box and Polygon on your models:
94
-
95
-
96
- class River
97
- include Mongoid::Document
98
- include Mongoid::Geospatial
99
-
100
- field :name, type: String
101
- field :length, type: Integer
102
- field :discharge, type: Integer
103
-
104
- field :source, type: Point, spatial: true
105
- field :mouth, type: Point, spatial: true
106
- field :course, type: Line
107
- field :boundings, type: Box
108
-
109
- # spatial indexing
110
- spatial_index :mouth
111
-
112
- # default mongodb options
113
- spatial_index :mouth, {bit: 24, min: -180, max: 180}
114
- end
115
-
116
-
117
- Use
118
- ---
119
-
120
47
  Generate indexes on MongoDB:
121
48
 
122
49
 
@@ -126,6 +53,10 @@ Generate indexes on MongoDB:
126
53
  Points
127
54
  ------
128
55
 
56
+ Currently, MongoDB supports query operations on 2D points only, so that's
57
+ what this lib does. All geometries apart from points are just arrays
58
+ in the database. Here's is how you can input a point as:
59
+
129
60
  * an unordered hash with the lat long string keys defined when setting the field (only applies for setting the field)
130
61
  * longitude latitude array in that order - [long,lat] ([x, y])
131
62
  * an unordered hash with latitude key(:lat, :latitude) and a longitude key(:lon, :long, :lng, :longitude)
@@ -150,10 +81,18 @@ We store data in the DB as a [lng,lat] array then reformat when it is returned t
150
81
  Now to access this spatial information we can do this
151
82
 
152
83
  hudson.mouth # => [-74.026667, 40.703056]
84
+
85
+ If you need a hash
86
+
87
+ hudson.mouth.to_hsh # => { x: -74.026667, y: 40.703056 }
88
+
89
+ If you are using GeoRuby or RGeo
90
+
91
+ hudson.mouth.to_geo # => NiceGeolib::Point
153
92
 
154
93
  Distance and other geometrical calculations are delegated to the external
155
94
  library you choosed. More info about using RGeo or GeoRuby below.
156
- Some built in helpers:
95
+ Some built in helpers for mongoid queries:
157
96
 
158
97
  # Returns middle point + radius
159
98
  # Useful to search #within_circle
@@ -165,6 +104,12 @@ Some built in helpers:
165
104
  hudson.mounth.to_hsh(:lon, :lat) # {:lon => -74.., :lat => 40..}
166
105
 
167
106
 
107
+ And for polygons and lines:
108
+
109
+ house.area.bbox # Returns polygon bounding_box (envelope)
110
+ house.area.center # Returns calculate middle point
111
+
112
+
168
113
  Query
169
114
  --------
170
115
 
@@ -178,30 +123,150 @@ All MongoDB queries are handled by Mongoid.
178
123
  You can use Geometry instance directly on any query:
179
124
 
180
125
  * near
126
+ * Bar.near(location: person.house)
181
127
  * Bar.where(:location.near => person.house)
128
+
182
129
 
183
130
  * near_sphere
131
+ * Bar.near_sphere(location: person.house)
184
132
  * Bar.where(:location.near_sphere => person.house)
185
133
 
134
+
186
135
  * within_box
187
- * Bar.where(:location.within_box => hood.area)
136
+ * Bar.within_box(location: hood.area)
137
+
188
138
 
189
139
  * within_circle
190
- * Bar.where(:location.within_box => hood.area)
140
+ * Bar.within_circle(location: hood.area)
141
+
191
142
 
192
143
  * within_circle_sphere
193
- * Bar.where(:location.within_circle_sphere => hood.area)
144
+ * Bar.within_circle_sphere(location: hood.area)
145
+
194
146
 
195
147
  * within_polygon
196
- * Bar.where(:location.within_polygon => city.area)
148
+ * Bar.within_polygon(location: city.area)
149
+
150
+
151
+ External Libraries
152
+ ------------------
153
+
154
+ Use RGeo?
155
+ https://github.com/dazuma/rgeo
156
+
157
+ RGeo is a Ruby wrapper for Proj/GEOS.
158
+ It's perfect when you need to work with complex calculations and projections.
159
+ It'll require more stuff installed to compile/work.
160
+
161
+
162
+ Use GeoRuby?
163
+ https://github.com/nofxx/geo_ruby
164
+
165
+ GeoRuby is a pure Ruby Geometry Library.
166
+ It's perfect if you want simple calculations and/or keep your stack in pure ruby.
167
+ Albeit not full featured in maths it has a handful of methods and good import/export helpers.
168
+
169
+ Use Nothing?
170
+
171
+ This lib won't stand in your way.
172
+ Write your own wrapper if you want.
173
+
174
+
175
+ Geometry Helpers
176
+ ----------------
177
+
178
+ We currently support GeoRuby and RGeo.
179
+ If you require one of those, a #to_geo method will be available to all
180
+ spatial fields, returning the external library corresponding object.
181
+ To illustrate:
182
+
183
+ class Person
184
+ include Mongoid::Document
185
+ include Mongoid::Geospatial
186
+
187
+ field :location, type: Point
188
+ end
189
+
190
+ me = Person.new(location: [8, 8])
191
+
192
+ # Example with GeoRuby
193
+ point.class # Mongoid::Geospatial::Point
194
+ point.to_geo.class # GeoRuby::SimpleFeatures::Point
195
+
196
+ # Example with RGeo
197
+ point.class # Mongoid::Geospatial::Point
198
+ point.to_geo.class # RGeo::Geographic::SphericalPointImpl
199
+
200
+
201
+ Configure
202
+ ----------------
203
+
204
+ Assemble it as you need (use a initializer file):
205
+
206
+ With RGeo
207
+
208
+ Mongoid::Geospatial.use_rgeo
209
+ # Optional
210
+ # Mongoid::Geospatial.factory = RGeo::Geographic.spherical_factory
211
+
212
+
213
+ With GeoRuby
214
+
215
+ Mongoid::Geospatial.use_georuby
216
+
217
+
218
+ Defaults (change if you know what you're doing)
219
+
220
+ Mongoid::Geospatial.lng_symbol = :x
221
+ Mongoid::Geospatial.lat_symbol = :y
222
+ Mongoid::Geospatial.earth_radius = EARTH_RADIUS
223
+
224
+
225
+
226
+ Model Setup
227
+ -----------
228
+
229
+ You can create Point, Line, Circle, Box and Polygon on your models:
230
+
231
+
232
+ class CrazyGeom
233
+ include Mongoid::Document
234
+ include Mongoid::Geospatial
235
+
236
+ field :location, type: Point
237
+
238
+ field :route, type: Line
239
+ field :area, type: Polygon
240
+
241
+ field :square, type: Box
242
+ field :around, type: Circle
243
+
244
+ # spatial indexing
245
+ spatial_index :mouth
246
+
247
+ # default mongodb options
248
+ spatial_index :mouth, {bit: 24, min: -180, max: 180}
249
+
250
+ # query by location
251
+ spatial_scope :location
252
+ end
253
+
254
+
255
+
256
+ Nearby
257
+ ------
197
258
 
259
+ You can add a `spatial_scope` on your models. So you can query:
198
260
 
199
- Class Methods
200
- -------------
261
+ Bar.nearby(my.location)
262
+
263
+ instead of
201
264
 
202
- Some method are added to your class when you define a field as spatial.
265
+ Bar.near(location: my.location)
266
+
267
+ Good when you're drunk. Just add to your model:
203
268
 
204
- field :location, type: Point, spatial: true
269
+ spatial_scope :<field>
205
270
 
206
271
 
207
272
 
@@ -25,8 +25,8 @@ module Mongoid
25
25
  [center, r]
26
26
  end
27
27
 
28
- def radius_sphere r = 1
29
- [center, r.to_f/Mongoid::Geospatial.earth_radius[:km]]
28
+ def radius_sphere r = 1, unit = :km
29
+ radius r.to_f/Mongoid::Geospatial.earth_radius[unit]
30
30
  end
31
31
 
32
32
 
@@ -1,6 +1,7 @@
1
1
  module Mongoid
2
2
  module Geospatial
3
3
  class Point
4
+ include Enumerable
4
5
  attr_accessor :x, :y
5
6
 
6
7
  def initialize(x=nil, y=nil)
@@ -18,6 +19,11 @@ module Mongoid
18
19
  mongoize[args]
19
20
  end
20
21
 
22
+ def each
23
+ yield x
24
+ yield y
25
+ end
26
+
21
27
  def to_hsh xl = :x, yl = :y
22
28
  {xl => x, yl => y}
23
29
  end
@@ -58,7 +64,7 @@ module Mongoid
58
64
 
59
65
  # Database -> Object
60
66
  def demongoize(object)
61
- # return unless object && !object.empty?
67
+ return unless object
62
68
  Point.new(*object)
63
69
  end
64
70
 
@@ -26,7 +26,7 @@ module Mongoid
26
26
  @@earth_radius = EARTH_RADIUS.dup
27
27
 
28
28
  included do
29
- attr_accessor :geo
29
+ # attr_accessor :geo
30
30
  cattr_accessor :spatial_fields, :spatial_fields_indexed
31
31
  @@spatial_fields = []
32
32
  @@spatial_fields_indexed = []
@@ -51,6 +51,15 @@ module Mongoid
51
51
  index({name => '2d'}, options)
52
52
  end
53
53
 
54
+ def spatial_scope field, opts = {}
55
+ self.singleton_class.class_eval do
56
+ # define_method(:close) do |args|
57
+ define_method(:nearby) do |args|
58
+ queryable.where(field.near_sphere => args)
59
+ end
60
+ end
61
+ end
62
+
54
63
  end
55
64
 
56
65
  end
@@ -1,5 +1,5 @@
1
1
  module Mongoid
2
2
  module Geospatial
3
- VERSION = "2.3.0"
3
+ VERSION = "2.5.0"
4
4
  end
5
5
  end
data/spec/models/bar.rb CHANGED
@@ -8,4 +8,6 @@ class Bar
8
8
  has_one :rating, :as => :ratable
9
9
 
10
10
  spatial_index :location
11
+ spatial_scope :location
12
+
11
13
  end
@@ -3,9 +3,14 @@ require "spec_helper"
3
3
  describe Mongoid::Fields do
4
4
 
5
5
  context "spatial" do
6
+ before do
7
+ Bar.create_indexes
8
+ end
6
9
 
7
10
  it "should set some class methods" do
8
- Bar.near_location([1,1]).should eq([])
11
+ far = Bar.create!(name: "Far", location: [7,7])
12
+ near = Bar.create!(name: "Near", location: [2,2])
13
+ Bar.nearby([1,1]).should eq([near, far])
9
14
  end
10
15
 
11
16
  end
@@ -0,0 +1,11 @@
1
+ require "spec_helper"
2
+
3
+ describe Mongoid::Geospatial::Box do
4
+
5
+ it "should work" do
6
+ alarm = Alarm.new(area: [[1,2], [3,4]])
7
+ alarm.area.should be_a Mongoid::Geospatial::Box
8
+ end
9
+
10
+
11
+ end
@@ -9,7 +9,14 @@ describe Mongoid::Geospatial::Point do
9
9
 
10
10
  it "should not fail if point is nil" do
11
11
  bar = Bar.create!(name: "Moe's")
12
- bar.location.x.should be_nil
12
+ bar.location.should be_nil
13
+ end
14
+
15
+ it "should set point to nil" do
16
+ bar = Bar.create!(name: "Moe's", location: [1, 1])
17
+ bar.location = nil
18
+ bar.location.should be_nil
19
+ bar.save.should be_true
13
20
  end
14
21
 
15
22
  describe "methods" do
@@ -36,6 +43,14 @@ describe Mongoid::Geospatial::Point do
36
43
  bar.location.radius_sphere[1].should be_within(0.0001).of(0.00015)
37
44
  end
38
45
 
46
+ it "should have a radius sphere helper in meters" do
47
+ bar.location.radius_sphere(1000, :m)[1].should be_within(0.0001).of(0.00015)
48
+ end
49
+
50
+ it "should have a radius sphere helper in miles" do
51
+ bar.location.radius_sphere(1, :mi)[1].should be_within(0.0001).of(0.00025)
52
+ end
53
+
39
54
  end
40
55
 
41
56
  describe "queryable" do
@@ -66,6 +81,15 @@ describe Mongoid::Geospatial::Point do
66
81
  Bar.where(:location.near => jim.location).should == [ paris, prague, berlin ]
67
82
  end
68
83
 
84
+ it "returns the documents sorted closest to furthest" do
85
+ Bar.near(location: jim.location).should == [ paris, prague, berlin ]
86
+ end
87
+
88
+ it "returns the documents sorted closest to furthest sphere" do
89
+ person = Person.new(:location => [ 41.23, 2.9 ])
90
+ Bar.near_sphere(location: jim.location).should == [ paris, prague, berlin ]
91
+ end
92
+
69
93
  it "returns the documents sorted closest to furthest sphere" do
70
94
  person = Person.new(:location => [ 41.23, 2.9 ])
71
95
  Bar.where(:location.near_sphere => jim.location).should == [ paris, prague, berlin ]
@@ -113,6 +137,11 @@ describe Mongoid::Geospatial::Point do
113
137
  it "returns the documents within a center_sphere" do
114
138
  Bar.where(:location.within_spherical_circle => [elvis.location, 0.5]).to_a.should include(mile9)
115
139
  end
140
+
141
+ it "returns the documents within a box" do
142
+ Bar.within_box(location: [elvis.location, elvis.location.map(&:ceil)]).to_a.should == [ mile3 ]
143
+ end
144
+
116
145
  end
117
146
 
118
147
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mongoid_geospatial
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.0
4
+ version: 2.5.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2012-09-13 00:00:00.000000000 Z
13
+ date: 2012-09-14 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rgeo
@@ -181,6 +181,7 @@ files:
181
181
  - spec/models/river.rb
182
182
  - spec/mongoid_geospatial/extensions/core_ext_spec.rb
183
183
  - spec/mongoid_geospatial/field_option_spec.rb
184
+ - spec/mongoid_geospatial/fields/box_spec.rb
184
185
  - spec/mongoid_geospatial/fields/circle_spec.rb
185
186
  - spec/mongoid_geospatial/fields/line_spec.rb
186
187
  - spec/mongoid_geospatial/fields/point_spec.rb
@@ -227,6 +228,7 @@ test_files:
227
228
  - spec/models/river.rb
228
229
  - spec/mongoid_geospatial/extensions/core_ext_spec.rb
229
230
  - spec/mongoid_geospatial/field_option_spec.rb
231
+ - spec/mongoid_geospatial/fields/box_spec.rb
230
232
  - spec/mongoid_geospatial/fields/circle_spec.rb
231
233
  - spec/mongoid_geospatial/fields/line_spec.rb
232
234
  - spec/mongoid_geospatial/fields/point_spec.rb