mongoid-geospatial 4.0.1 → 5.0.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.
- checksums.yaml +4 -4
- data/.travis.yml +2 -0
- data/README.md +126 -242
- data/bench/bench +11 -10
- data/lib/mongoid/geospatial.rb +14 -17
- data/lib/mongoid/geospatial/fields/point.rb +42 -10
- data/lib/mongoid/geospatial/geometry_field.rb +25 -2
- data/lib/mongoid/geospatial/helpers/delegate.rb +6 -2
- data/lib/mongoid/geospatial/version.rb +1 -1
- data/lib/mongoid/geospatial/wrappers/georuby.rb +4 -0
- data/lib/mongoid/geospatial/wrappers/rgeo.rb +4 -1
- data/mongoid-geospatial.gemspec +2 -2
- data/spec/models/bar.rb +1 -1
- data/spec/models/farm.rb +1 -1
- data/spec/models/person.rb +2 -1
- data/spec/models/river.rb +7 -7
- data/spec/mongoid/geospatial/fields/line_string_spec.rb +44 -8
- data/spec/mongoid/geospatial/fields/point_spec.rb +30 -28
- data/spec/mongoid/geospatial/fields/polygon_spec.rb +25 -18
- data/spec/mongoid/geospatial/geospatial_spec.rb +65 -49
- data/spec/mongoid/geospatial/helpers/core_spec.rb +8 -3
- data/spec/mongoid/geospatial/helpers/delegate_spec.rb +18 -1
- data/spec/mongoid/geospatial/helpers/spatial_spec.rb +9 -1
- data/spec/mongoid/geospatial/helpers/sphere_spec.rb +10 -1
- data/spec/mongoid/geospatial/wrappers/rgeo_spec.rb +4 -2
- data/spec/spec_helper.rb +7 -3
- metadata +5 -5
data/bench/bench
CHANGED
@@ -2,12 +2,12 @@
|
|
2
2
|
#
|
3
3
|
# Just for fun
|
4
4
|
#
|
5
|
-
|
5
|
+
$LOAD_PATH << File.expand_path('../../lib', __FILE__)
|
6
6
|
|
7
7
|
require 'mongoid/geospatial'
|
8
8
|
|
9
9
|
Mongoid.configure do |config|
|
10
|
-
config.connect_to(
|
10
|
+
config.connect_to('mongoid_geospatial_bench')
|
11
11
|
end
|
12
12
|
|
13
13
|
Mongoid::Geospatial.with_georuby!
|
@@ -36,27 +36,28 @@ Mongoid.purge!
|
|
36
36
|
|
37
37
|
Benchmark.bmbm do |b|
|
38
38
|
[100, 1000, 3000].each do |t|
|
39
|
-
nogeo
|
39
|
+
nogeo = []
|
40
|
+
cafes = []
|
40
41
|
b.report("#{t} W NoGeo") do
|
41
42
|
t.times { nogeo << NoGeo.create(name: 'Boring').id }
|
42
43
|
end
|
43
44
|
b.report("#{t} W Rider") { t.times { Rider.create(name: 'Munro') } }
|
44
45
|
|
45
46
|
b.report("#{t} W Cafe ") do
|
46
|
-
t.times { cafes << Cafe.create(name: 'Bacco', spot: [3,3]).id }
|
47
|
+
t.times { cafes << Cafe.create(name: 'Bacco', spot: [3, 3]).id }
|
47
48
|
end
|
48
49
|
# puts "---"
|
49
|
-
b.report("#{t} R NoGeo") { nogeo.each { |id| NoGeo.find(id) }}
|
50
|
+
b.report("#{t} R NoGeo") { nogeo.each { |id| NoGeo.find(id) } }
|
50
51
|
# b.report("#{t} R Rider") { t.times { Rider.create(name: 'Munro') } }
|
51
|
-
b.report("#{t} R Cafe ") { cafes.each { |id| Cafe.find(id) }}
|
52
|
-
b.report("#{t} R Cafe Georuby") { cafes.each { |id| Cafe.find(id).spot.to_geo }}
|
53
|
-
b.report("#{t} R Cafe RGeo") { cafes.each { |id| Cafe.find(id).spot.to_rgeo }}
|
52
|
+
b.report("#{t} R Cafe ") { cafes.each { |id| Cafe.find(id) } }
|
53
|
+
b.report("#{t} R Cafe Georuby") { cafes.each { |id| Cafe.find(id).spot.to_geo } }
|
54
|
+
b.report("#{t} R Cafe RGeo") { cafes.each { |id| Cafe.find(id).spot.to_rgeo } }
|
54
55
|
end
|
55
|
-
b.report(
|
56
|
+
b.report('R Cafe GeoRuby') do
|
56
57
|
cafe = Cafe.first
|
57
58
|
1_000_000.times { cafe.spot.to_geo }
|
58
59
|
end
|
59
|
-
b.report(
|
60
|
+
b.report('R Cafe RGeo') do
|
60
61
|
cafe = Cafe.first
|
61
62
|
1_000_000.times { cafe.spot.to_rgeo }
|
62
63
|
end
|
data/lib/mongoid/geospatial.rb
CHANGED
@@ -6,23 +6,22 @@ require 'mongoid/geospatial/helpers/sphere'
|
|
6
6
|
require 'mongoid/geospatial/helpers/delegate'
|
7
7
|
|
8
8
|
module Mongoid
|
9
|
-
|
10
9
|
#
|
11
10
|
# Main Geospatial module
|
12
11
|
#
|
13
12
|
# include Mongoid::Geospatial
|
14
13
|
#
|
15
14
|
module Geospatial
|
16
|
-
autoload :GeometryField,
|
15
|
+
autoload :GeometryField, 'mongoid/geospatial/geometry_field'
|
17
16
|
|
18
|
-
autoload :Point,
|
19
|
-
autoload :LineString,
|
20
|
-
autoload :Polygon,
|
17
|
+
autoload :Point, 'mongoid/geospatial/fields/point'
|
18
|
+
autoload :LineString, 'mongoid/geospatial/fields/line_string'
|
19
|
+
autoload :Polygon, 'mongoid/geospatial/fields/polygon'
|
21
20
|
|
22
|
-
autoload :Box,
|
23
|
-
autoload :Circle,
|
21
|
+
autoload :Box, 'mongoid/geospatial/fields/box'
|
22
|
+
autoload :Circle, 'mongoid/geospatial/fields/circle'
|
24
23
|
|
25
|
-
autoload :VERSION,
|
24
|
+
autoload :VERSION, 'mongoid/geospatial/version'
|
26
25
|
|
27
26
|
extend ActiveSupport::Concern
|
28
27
|
|
@@ -70,6 +69,7 @@ module Mongoid
|
|
70
69
|
require 'mongoid/geospatial/wrappers/georuby'
|
71
70
|
end
|
72
71
|
|
72
|
+
# Methods applied to Document's class
|
73
73
|
module ClassMethods
|
74
74
|
#
|
75
75
|
# Create Spatial index for given field
|
@@ -78,7 +78,8 @@ module Mongoid
|
|
78
78
|
# @param [String,Symbol] name
|
79
79
|
# @param [Hash] options options for spatial_index
|
80
80
|
#
|
81
|
-
# http://www.mongodb.org/display/DOCS/Geospatial+Indexing
|
81
|
+
# http://www.mongodb.org/display/DOCS/Geospatial+Indexing
|
82
|
+
# #GeospatialIndexing-geoNearCommand
|
82
83
|
#
|
83
84
|
def spatial_index(name, options = {})
|
84
85
|
spatial_fields_indexed << name
|
@@ -92,7 +93,8 @@ module Mongoid
|
|
92
93
|
# @param [String,Symbol] name
|
93
94
|
# @param [Hash] options options for spatial_index
|
94
95
|
#
|
95
|
-
# http://www.mongodb.org/display/DOCS/Geospatial+Indexing
|
96
|
+
# http://www.mongodb.org/display/DOCS/Geospatial+Indexing
|
97
|
+
# #GeospatialIndexing-geoNearCommand
|
96
98
|
def sphere_index(name, options = {})
|
97
99
|
spatial_fields_indexed << name
|
98
100
|
index({ name => '2dsphere' }, options)
|
@@ -105,7 +107,8 @@ module Mongoid
|
|
105
107
|
# @param [String,Symbol] name
|
106
108
|
# @param [Hash] options options for spatial_index
|
107
109
|
#
|
108
|
-
# http://www.mongodb.org/display/DOCS/Geospatial+Indexing
|
110
|
+
# http://www.mongodb.org/display/DOCS/Geospatial+Indexing
|
111
|
+
# #GeospatialIndexing-geoNearCommand
|
109
112
|
def spatial_scope(field, _opts = {})
|
110
113
|
singleton_class.class_eval do
|
111
114
|
# define_method(:close) do |args|
|
@@ -114,12 +117,6 @@ module Mongoid
|
|
114
117
|
end
|
115
118
|
end
|
116
119
|
end
|
117
|
-
|
118
|
-
private
|
119
|
-
def geo_field(name, options = {})
|
120
|
-
field name, { type: Mongoid::Geospatial::Point,
|
121
|
-
spatial: true }.merge(options)
|
122
|
-
end
|
123
120
|
end
|
124
121
|
end
|
125
122
|
end
|
@@ -4,10 +4,12 @@ module Mongoid
|
|
4
4
|
#
|
5
5
|
class Point
|
6
6
|
include Enumerable
|
7
|
-
|
7
|
+
attr_accessor :x, :y, :z
|
8
8
|
|
9
9
|
def initialize(x, y, z = nil)
|
10
|
-
@x
|
10
|
+
@x = x
|
11
|
+
@y = y
|
12
|
+
@z = z
|
11
13
|
end
|
12
14
|
|
13
15
|
# Object -> Database
|
@@ -29,21 +31,33 @@ module Mongoid
|
|
29
31
|
yield x
|
30
32
|
yield y
|
31
33
|
end
|
34
|
+
|
32
35
|
#
|
33
36
|
# Point representation as a Hash
|
34
37
|
#
|
35
|
-
# @return
|
38
|
+
# @return [Hash] with { xl => x, yl => y }
|
39
|
+
#
|
36
40
|
def to_hsh(xl = :x, yl = :y)
|
37
41
|
{ xl => x, yl => y }
|
38
42
|
end
|
39
43
|
alias_method :to_hash, :to_hsh
|
40
44
|
|
45
|
+
#
|
41
46
|
# Helper for [self, radius]
|
47
|
+
#
|
48
|
+
# @return [Array] with [self, radius]
|
49
|
+
#
|
42
50
|
def radius(r = 1)
|
43
51
|
[mongoize, r]
|
44
52
|
end
|
45
53
|
|
46
|
-
#
|
54
|
+
#
|
55
|
+
# Radius Sphere
|
56
|
+
#
|
57
|
+
# Validates that #x & #y are `Numeric`
|
58
|
+
#
|
59
|
+
# @return [Array] with [self, radius / earth radius]
|
60
|
+
#
|
47
61
|
def radius_sphere(r = 1, unit = :km)
|
48
62
|
radius r.to_f / Mongoid::Geospatial.earth_radius[unit]
|
49
63
|
end
|
@@ -51,7 +65,9 @@ module Mongoid
|
|
51
65
|
#
|
52
66
|
# Am I valid?
|
53
67
|
#
|
54
|
-
# Validates that x & y are `Numeric`
|
68
|
+
# Validates that #x & #y are `Numeric`
|
69
|
+
#
|
70
|
+
# @return [Boolean] if self #x && #y are valid
|
55
71
|
#
|
56
72
|
def valid?
|
57
73
|
x && y && x.is_a?(Numeric) && y.is_a?(Numeric)
|
@@ -63,10 +79,23 @@ module Mongoid
|
|
63
79
|
# "x, y"
|
64
80
|
#
|
65
81
|
# @return [String] Point as comma separated String
|
82
|
+
#
|
66
83
|
def to_s
|
67
84
|
"#{x}, #{y}"
|
68
85
|
end
|
69
86
|
|
87
|
+
#
|
88
|
+
# Point inverse/reverse
|
89
|
+
#
|
90
|
+
# MongoDB: "x, y"
|
91
|
+
# Reverse: "y, x"
|
92
|
+
#
|
93
|
+
# @return [Array] Point reversed: "y, x"
|
94
|
+
#
|
95
|
+
def reverse
|
96
|
+
[y, x]
|
97
|
+
end
|
98
|
+
|
70
99
|
#
|
71
100
|
# Distance calculation methods. Thinking about not using it
|
72
101
|
# One needs to choose and external lib. GeoRuby or RGeo
|
@@ -100,7 +129,7 @@ module Mongoid
|
|
100
129
|
# Database -> Object
|
101
130
|
# Get it back
|
102
131
|
def demongoize(obj)
|
103
|
-
obj &&
|
132
|
+
obj && new(*obj)
|
104
133
|
end
|
105
134
|
|
106
135
|
#
|
@@ -122,7 +151,10 @@ module Mongoid
|
|
122
151
|
# Converts the object that was supplied to a criteria
|
123
152
|
# into a database friendly form.
|
124
153
|
def evolve(obj)
|
125
|
-
|
154
|
+
case obj
|
155
|
+
when Point then obj.mongoize
|
156
|
+
else obj
|
157
|
+
end
|
126
158
|
end
|
127
159
|
|
128
160
|
private
|
@@ -151,9 +183,9 @@ module Mongoid
|
|
151
183
|
#
|
152
184
|
# @return (Array)
|
153
185
|
#
|
154
|
-
def from_array(
|
155
|
-
return nil if
|
156
|
-
|
186
|
+
def from_array(array)
|
187
|
+
return nil if array.empty?
|
188
|
+
array.flatten[0..1].map(&:to_f)
|
157
189
|
end
|
158
190
|
|
159
191
|
#
|
@@ -1,5 +1,6 @@
|
|
1
1
|
module Mongoid
|
2
2
|
module Geospatial
|
3
|
+
#
|
3
4
|
#
|
4
5
|
# Main Geometry Array
|
5
6
|
#
|
@@ -8,8 +9,12 @@ module Mongoid
|
|
8
9
|
#
|
9
10
|
class GeometryField < Array
|
10
11
|
#
|
11
|
-
#
|
12
|
+
#
|
13
|
+
# Determines the 2 points geometry bounding box.
|
12
14
|
# Useful to find map boundaries, and fit to screen.
|
15
|
+
# Returns [bottom left, top right]
|
16
|
+
#
|
17
|
+
# @return [Array] containing 2 points
|
13
18
|
#
|
14
19
|
def bounding_box
|
15
20
|
max_x, min_x = -Float::MAX, Float::MAX
|
@@ -24,10 +29,26 @@ module Mongoid
|
|
24
29
|
end
|
25
30
|
alias_method :bbox, :bounding_box
|
26
31
|
|
32
|
+
#
|
33
|
+
# Determines the 5 points geometry bounding box.
|
34
|
+
# Useful to use with Mongoid #within_geometry
|
35
|
+
#
|
36
|
+
# Returns a closed ring:
|
37
|
+
# [bottom left, top left, top right, bottom right, bottom left]
|
38
|
+
#
|
39
|
+
# @return [Array] containing 5 points
|
40
|
+
#
|
41
|
+
def geom_box
|
42
|
+
xl, yl = bounding_box
|
43
|
+
[xl, [xl[0], yl[1]], yl, [yl[0], xl[1]], xl]
|
44
|
+
end
|
45
|
+
|
27
46
|
#
|
28
47
|
# Determines the center point of a multi point geometry.
|
29
48
|
# Geometry may be closed or not.
|
30
49
|
#
|
50
|
+
# @return [Array] containing 1 point [x,y]
|
51
|
+
#
|
31
52
|
def center_point
|
32
53
|
min, max = *bbox
|
33
54
|
[(min[0] + max[0]) / 2.0, (min[1] + max[1]) / 2.0]
|
@@ -39,6 +60,7 @@ module Mongoid
|
|
39
60
|
#
|
40
61
|
# @param [Numeric] r radius
|
41
62
|
# @return [Array] [point, r] point and radius in mongoid format
|
63
|
+
#
|
42
64
|
def radius(r = 1)
|
43
65
|
[center, r]
|
44
66
|
end
|
@@ -49,7 +71,7 @@ module Mongoid
|
|
49
71
|
# point.radius(x) -> [point, x / earth radius]
|
50
72
|
#
|
51
73
|
# @see Point#radius
|
52
|
-
# @return
|
74
|
+
# @return [Array]
|
53
75
|
#
|
54
76
|
def radius_sphere(r = 1, unit = :km)
|
55
77
|
radius r.to_f / Mongoid::Geospatial.earth_radius[unit]
|
@@ -59,6 +81,7 @@ module Mongoid
|
|
59
81
|
#
|
60
82
|
# Database -> Object
|
61
83
|
#
|
84
|
+
# @return [Object]
|
62
85
|
def demongoize(obj)
|
63
86
|
obj && new(obj)
|
64
87
|
end
|
@@ -18,11 +18,15 @@ Mongoid::Fields.option :delegate do |model, field, options|
|
|
18
18
|
end
|
19
19
|
|
20
20
|
define_method "#{x_meth}=" do |arg|
|
21
|
-
|
21
|
+
# HACK: Mongoid has detecting an Array changed
|
22
|
+
# self[field.name][0] = arg
|
23
|
+
send("#{field.name}=", [arg, self[field.name][1]])
|
22
24
|
end
|
23
25
|
|
24
26
|
define_method "#{y_meth}=" do |arg|
|
25
|
-
self[field.name][1] = arg
|
27
|
+
# self[field.name][1] = arg
|
28
|
+
# self[field.name] = [self[field.name][0], arg]
|
29
|
+
send("#{field.name}=", [self[field.name][0], arg])
|
26
30
|
end
|
27
31
|
end
|
28
32
|
end
|
@@ -2,6 +2,10 @@ require 'rgeo'
|
|
2
2
|
require 'mongoid/geospatial/ext/rgeo_spherical_point_impl'
|
3
3
|
|
4
4
|
module Mongoid
|
5
|
+
#
|
6
|
+
# Wrappers for RGeo
|
7
|
+
# https://github.com/rgeo/rgeo
|
8
|
+
#
|
5
9
|
module Geospatial
|
6
10
|
# Wrapper to Rgeo's Point
|
7
11
|
Point.class_eval do
|
@@ -24,7 +28,6 @@ module Mongoid
|
|
24
28
|
|
25
29
|
# Rgeo's GeometryField concept
|
26
30
|
GeometryField.class_eval do
|
27
|
-
|
28
31
|
def points
|
29
32
|
map do |pair|
|
30
33
|
RGeo::Geographic.spherical_factory.point(*pair)
|
data/mongoid-geospatial.gemspec
CHANGED
@@ -4,8 +4,8 @@ require File.expand_path('../lib/mongoid/geospatial/version', __FILE__)
|
|
4
4
|
Gem::Specification.new do |gem|
|
5
5
|
gem.authors = ['Ryan Ong', 'Marcos Piccinini']
|
6
6
|
gem.email = ['use@git.hub.com']
|
7
|
-
gem.description = 'Mongoid Extension that simplifies MongoDB casting and operations on spatial Ruby objects.'
|
8
7
|
gem.summary = 'Mongoid Extension that simplifies MongoDB Geospatial Operations.'
|
8
|
+
gem.description = 'Mongoid Extension that simplifies MongoDB casting and operations on spatial Ruby objects.'
|
9
9
|
gem.homepage = 'https://github.com/nofxx/mongoid-geospatial'
|
10
10
|
|
11
11
|
gem.files = `git ls-files`.split("\n")
|
@@ -15,5 +15,5 @@ Gem::Specification.new do |gem|
|
|
15
15
|
gem.version = Mongoid::Geospatial::VERSION
|
16
16
|
gem.license = 'MIT'
|
17
17
|
|
18
|
-
gem.add_dependency('mongoid', ['>=
|
18
|
+
gem.add_dependency('mongoid', ['>= 5.0.0.beta'])
|
19
19
|
end
|
data/spec/models/bar.rb
CHANGED
data/spec/models/farm.rb
CHANGED
data/spec/models/person.rb
CHANGED
@@ -26,7 +26,8 @@ class Person
|
|
26
26
|
field :employer_id
|
27
27
|
field :security_code
|
28
28
|
field :blood_alcohol_content, type: Float, default: -> { 0.0 }
|
29
|
-
field :last_drink_taken_at, type: Date,
|
29
|
+
field :last_drink_taken_at, type: Date,
|
30
|
+
default: -> { 1.day.ago.in_time_zone('Alaska') }
|
30
31
|
|
31
32
|
# Geo
|
32
33
|
field :location, type: Point
|
data/spec/models/river.rb
CHANGED
@@ -3,14 +3,14 @@ class River
|
|
3
3
|
include Mongoid::Document
|
4
4
|
include Mongoid::Geospatial
|
5
5
|
|
6
|
-
field :name,
|
7
|
-
field :length,
|
8
|
-
field :discharge,
|
9
|
-
field :course,
|
6
|
+
field :name, type: String
|
7
|
+
field :length, type: Integer
|
8
|
+
field :discharge, type: Integer
|
9
|
+
field :course, type: LineString, spatial: true
|
10
10
|
# set return_array to true if you do not want a hash returned all the time
|
11
|
-
field :source,
|
12
|
-
field :mouth,
|
13
|
-
field :mouth_array, type: Array,
|
11
|
+
field :source, type: Point, spatial: true
|
12
|
+
field :mouth, type: Point, spatial: { lat: 'latitude', lng: 'longitude' }
|
13
|
+
field :mouth_array, type: Array, spatial: { return_array: true }
|
14
14
|
|
15
15
|
# simplified spatial indexing
|
16
16
|
# you can only index one field in mongodb < 1.9
|