geomodel 0.0.1 → 0.0.2
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/CHANGELOG.md +4 -1
- data/README.md +24 -6
- data/lib/geomodel.rb +1 -1
- data/lib/geomodel/geocell.rb +15 -14
- data/lib/geomodel/geotypes.rb +1 -1
- data/lib/geomodel/version.rb +1 -1
- data/spec/geocell_spec.rb +44 -0
- data/spec/geotypes_spec.rb +28 -1
- data/spec/spec_helper.rb +3 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 90db919642b9d8269c289645bf18195b8efeb665
|
4
|
+
data.tar.gz: 1278b9035c58e080d225e81aebc38ac7cf1a4b22
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3f471cead361f81bfa870db73eb9ad372f177cf77e6dfb329be0b8fce036e3dc16020f650ae384a7a5a5c9ddeb845058016477512aa95cd368d87fb9b150c9e6
|
7
|
+
data.tar.gz: 17bc0e26b4f43181c3cb22cf398714fb65457bab4ddc495ae4928aba532f095eef9d8b5e6f303252ec5907283bd89ab06885dd6c7c0ffc49739aa90500831862
|
data/CHANGELOG.md
CHANGED
@@ -1,2 +1,5 @@
|
|
1
1
|
### 0.0.1 (January 2, 2014)
|
2
|
-
* Initial release - Straight port from Python, Java and JS implementations
|
2
|
+
* Initial release - Straight port from Python, Java and JS implementations
|
3
|
+
|
4
|
+
### 0.0.2 (January 5, 2014)
|
5
|
+
* Upped the test coverage (which revealed some pretty blatant bugs)
|
data/README.md
CHANGED
@@ -68,10 +68,13 @@ indexed and filtered by either conformance to a bounding box or by proximity
|
|
68
68
|
# Approach
|
69
69
|
|
70
70
|
This Ruby implementation of GeoModel is based on the Python, Java and JavaScript implementations.
|
71
|
-
It's implemented as class level methods contained modules and a few datatype classes. So the
|
72
|
-
part isn't quite there and I don't really see a need for it. Since the library is meant to
|
73
|
-
Non-Relational/Non-ORM environmets, binding the functions/methods to a model does not make
|
71
|
+
It's implemented as class level methods contained within modules and a few datatype classes. So the
|
72
|
+
'model' part isn't quite there and I don't really see a need for it. Since the library is meant to
|
73
|
+
be use in Non-Relational/Non-ORM environmets, binding the functions/methods to a model does not make
|
74
|
+
much sense.
|
75
|
+
|
74
76
|
The model part was mostly implemented in the other libraries to bind directly to Google App Engine.
|
77
|
+
The idea here is to make it backend/db independent and use callbacks to integrate with the backend.
|
75
78
|
|
76
79
|
# References
|
77
80
|
|
@@ -100,7 +103,7 @@ Or install it yourself as:
|
|
100
103
|
Currently, only single-point entities and two types of basic geospatial queries
|
101
104
|
on those entities are supported.
|
102
105
|
|
103
|
-
### Representing your
|
106
|
+
### Representing your Locations
|
104
107
|
|
105
108
|
You'll need a class to hold a geolocation. It assumes that an "entity" has a unique
|
106
109
|
"id" (specific field can be configure), a latitude/longitude combination stored in
|
@@ -125,6 +128,21 @@ flw_spire = Entity.new
|
|
125
128
|
flw_spire.id = 'Flatiron'
|
126
129
|
flw_spire.location = Geomodel::Types::Point.new(33.633406, -111.916803)
|
127
130
|
flw_spire.geocells = Geomodel::GeoCell.generate_geocells(flw_spire.location)
|
131
|
+
|
132
|
+
puts flw_spire.geocells
|
133
|
+
# 8
|
134
|
+
# 8d
|
135
|
+
# 8da
|
136
|
+
# 8daa
|
137
|
+
# 8daab
|
138
|
+
# 8daab6
|
139
|
+
# 8daab66
|
140
|
+
# 8daab666
|
141
|
+
# 8daab6668
|
142
|
+
# 8daab66684
|
143
|
+
# 8daab66684e
|
144
|
+
# 8daab66684e4
|
145
|
+
# 8daab66684e4d
|
128
146
|
```
|
129
147
|
|
130
148
|
### Bounding Box Queries
|
@@ -147,7 +165,7 @@ result_set = my_db.query('SELECT * WHERE location_geocells IN (?)', query_geocel
|
|
147
165
|
matches = Geomodel.filter_result_set_by_bounding_box(bounding_box, result_set)
|
148
166
|
```
|
149
167
|
|
150
|
-
###
|
168
|
+
### Proximity (nearest-n) Queries
|
151
169
|
|
152
170
|
Find nearby locations given a location (lat & lon) and a radius in meters:
|
153
171
|
|
@@ -189,4 +207,4 @@ distances = results.map(&:last)
|
|
189
207
|
|
190
208
|
## License
|
191
209
|
|
192
|
-
MIT License
|
210
|
+
MIT License
|
data/lib/geomodel.rb
CHANGED
@@ -84,7 +84,7 @@ module Geomodel
|
|
84
84
|
while !cur_geocells.empty?
|
85
85
|
closest_possible_next_result_dist = sorted_edge_distances[0]
|
86
86
|
|
87
|
-
next if max_distance
|
87
|
+
next if max_distance && closest_possible_next_result_dist > max_distance
|
88
88
|
|
89
89
|
cur_geocells_unique = cur_geocells - searched_cells.to_a
|
90
90
|
|
data/lib/geomodel/geocell.rb
CHANGED
@@ -267,7 +267,7 @@ module Geomodel
|
|
267
267
|
cell_adj_arr = cell.split(//) # Split the geocell string characters into a list.
|
268
268
|
i = cell_adj_arr.size - 1
|
269
269
|
|
270
|
-
while i >= 0 && (dx != 0
|
270
|
+
while i >= 0 && (dx != 0 || dy != 0)
|
271
271
|
x, y = subdiv_xy(cell_adj_arr[i])
|
272
272
|
|
273
273
|
# Horizontal adjacency.
|
@@ -339,24 +339,25 @@ module Geomodel
|
|
339
339
|
if between_w_e
|
340
340
|
if between_n_s
|
341
341
|
# Inside the geocell.
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
342
|
+
|
343
|
+
return [Geomodel::Math.distance(point, Geomodel::Types::Point.new(bbox.south, point.lon)),
|
344
|
+
Geomodel::Math.distance(point, Geomodel::Types::Point.new(bbox.north, point.lon)),
|
345
|
+
Geomodel::Math.distance(point, Geomodel::Types::Point.new(point.lat, bbox.east)),
|
346
|
+
Geomodel::Math.distance(point, Geomodel::Types::Point.new(point.lat, bbox.west))].min
|
346
347
|
else
|
347
|
-
return [
|
348
|
-
|
348
|
+
return [Geomodel::Math.distance(point, Geomodel::Types::Point.new(bbox.south, point.lon)),
|
349
|
+
Geomodel::Math.distance(point, Geomodel::Types::Point.new(bbox.north, point.lon))].min
|
349
350
|
end
|
350
351
|
else
|
351
352
|
if between_n_s
|
352
|
-
return [
|
353
|
-
|
353
|
+
return [Geomodel::Math.distance(point, Geomodel::Types::Point.new(point.lat, bbox.east)),
|
354
|
+
Geomodel::Math.distance(point, Geomodel::Types::Point.new(point.lat, bbox.west))].min
|
354
355
|
else
|
355
356
|
# TODO(romannurik): optimize
|
356
|
-
return [
|
357
|
-
|
358
|
-
|
359
|
-
|
357
|
+
return [Geomodel::Math.distance(point, Geomodel::Types::Point.new(bbox.south, bbox.east)),
|
358
|
+
Geomodel::Math.distance(point, Geomodel::Types::Point.new(bbox.north, bbox.east)),
|
359
|
+
Geomodel::Math.distance(point, Geomodel::Types::Point.new(bbox.south, bbox.west)),
|
360
|
+
Geomodel::Math.distance(point, Geomodel::Types::Point.new(bbox.north, bbox.west))].min
|
360
361
|
end
|
361
362
|
end
|
362
363
|
end
|
@@ -444,7 +445,7 @@ module Geomodel
|
|
444
445
|
# For example, the immediate children of 'a' are 'a0', 'a1', ..., 'af'.
|
445
446
|
#
|
446
447
|
def self.children(cell)
|
447
|
-
GEOCELL_ALPHABET.map { |chr| cell + chr }
|
448
|
+
GEOCELL_ALPHABET.split(//).map { |chr| cell + chr }
|
448
449
|
end
|
449
450
|
|
450
451
|
# Returns the (x, y) of the geocell character in the 4x4 alphabet grid.
|
data/lib/geomodel/geotypes.rb
CHANGED
data/lib/geomodel/version.rb
CHANGED
data/spec/geocell_spec.rb
CHANGED
@@ -58,6 +58,26 @@ describe 'Geomodel::GeoCell' do
|
|
58
58
|
expect(all_adjacents.size).to eq(8)
|
59
59
|
end
|
60
60
|
|
61
|
+
it "can determine adjacency left and bottom of parent cell" do
|
62
|
+
cells = {
|
63
|
+
"8e6187fe6187fa" => ["8e6187fe618d45", "8e6187fe618d50", "8e6187fe618d51", "8e6187fe6187fb", "8e6187fe6187f9", "8e6187fe6187f8", "8e6187fe6187ed", "8e6187fe6187ef"],
|
64
|
+
"8e6187fe618d45" => ["8e6187fe618d46", "8e6187fe618d47", "8e6187fe618d52", "8e6187fe618d50", "8e6187fe6187fa", "8e6187fe6187ef", "8e6187fe6187ee", "8e6187fe618d44"]
|
65
|
+
}
|
66
|
+
cells.each do |cell, adjacents|
|
67
|
+
expect(Geomodel::GeoCell.all_adjacents(cell)).to eq(adjacents)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
it "cam calculate the immediate children of a given geocell" do
|
72
|
+
expect(Geomodel::GeoCell.children("8e6187fe6187f")).
|
73
|
+
to eq(
|
74
|
+
%w(8e6187fe6187f0 8e6187fe6187f1 8e6187fe6187f2 8e6187fe6187f3
|
75
|
+
8e6187fe6187f4 8e6187fe6187f5 8e6187fe6187f6 8e6187fe6187f7
|
76
|
+
8e6187fe6187f8 8e6187fe6187f9 8e6187fe6187fa 8e6187fe6187fb
|
77
|
+
8e6187fe6187fc 8e6187fe6187fd 8e6187fe6187fe 8e6187fe6187ff)
|
78
|
+
)
|
79
|
+
end
|
80
|
+
|
61
81
|
it "can determine collinearity" do
|
62
82
|
cell = Geomodel::GeoCell.compute(Geomodel::Types::Point.new(37, -122), 14)
|
63
83
|
|
@@ -109,6 +129,30 @@ describe 'Geomodel::GeoCell' do
|
|
109
129
|
expect(geocells).to include("9aa228a8b3b00")
|
110
130
|
end
|
111
131
|
|
132
|
+
it "can calculate that the shortest distance between a point and a geocell bounding boxfor the point is effectively zero" do
|
133
|
+
point = Geomodel::Types::Point.new(40.7407092, -73.9894039)
|
134
|
+
cell = "9ac7be064ea77"
|
135
|
+
expect(Geomodel::GeoCell.point_distance(cell, point)).to be_within(0.2).of(0.0)
|
136
|
+
end
|
137
|
+
|
138
|
+
it "can calculate the shortest distance between a point outside a geocell and the geocell" do
|
139
|
+
point = Geomodel::Types::Point.new(40.7425610, -73.9922670)
|
140
|
+
cell = "9ac7be064ea77"
|
141
|
+
expect(Geomodel::GeoCell.point_distance(cell, point)).to be_within(0.2).of(317.2)
|
142
|
+
end
|
143
|
+
|
144
|
+
it "can calculate the shortest distance between a point between north and south (but not between east and west) of a geocell bounding box" do
|
145
|
+
point = Geomodel::Types::Point.new(40.740710, -74.025537)
|
146
|
+
cell = "9ac7be064ea77"
|
147
|
+
expect(Geomodel::GeoCell.point_distance(cell, point)).to be_within(0.2).of(3047.3)
|
148
|
+
end
|
149
|
+
|
150
|
+
it "can calculate the shortest distance between a point between east and west (but not between north and south) of a geocell bounding box" do
|
151
|
+
point = Geomodel::Types::Point.new(40.740720, -73.989403)
|
152
|
+
cell = "9ac7be064ea77"
|
153
|
+
expect(Geomodel::GeoCell.point_distance(cell, point)).to be_within(0.2).of(0.99)
|
154
|
+
end
|
155
|
+
|
112
156
|
# TODO implement these tests!
|
113
157
|
|
114
158
|
# @Test
|
data/spec/geotypes_spec.rb
CHANGED
@@ -54,12 +54,39 @@ describe 'Geomodel::Types' do
|
|
54
54
|
expect(box_a).to eq(box_b)
|
55
55
|
end
|
56
56
|
|
57
|
-
it "can be created with north below south" do
|
57
|
+
it "can't be created with north below south" do
|
58
58
|
box = Geomodel::Types::Box.new(37, -122, 34, -125)
|
59
59
|
|
60
60
|
expect { box.north = 32 }.to raise_error
|
61
61
|
expect { box.south = 39 }.to raise_error
|
62
62
|
end
|
63
|
+
|
64
|
+
it "can be created with south below north" do
|
65
|
+
box = Geomodel::Types::Box.new(37, -122, 34, -125)
|
66
|
+
|
67
|
+
expect { box.north = 39 }.to_not raise_error
|
68
|
+
expect { box.south = 32 }.to_not raise_error
|
69
|
+
end
|
70
|
+
|
71
|
+
it "can be set the values for north, east, south and west" do
|
72
|
+
box = Geomodel::Types::Box.new(37, -122, 34, -125)
|
73
|
+
|
74
|
+
expect { box.north = 39 }.to_not raise_error
|
75
|
+
expect { box.south = 32 }.to_not raise_error
|
76
|
+
expect { box.east = -123 }.to_not raise_error
|
77
|
+
expect { box.west = -126 }.to_not raise_error
|
78
|
+
|
79
|
+
expect(box.north).to eq(39)
|
80
|
+
expect(box.south).to eq(32)
|
81
|
+
expect(box.east).to eq(-123)
|
82
|
+
expect(box.west).to eq(-126)
|
83
|
+
end
|
84
|
+
|
85
|
+
it "returns a suitable string representation" do
|
86
|
+
box = Geomodel::Types::Box.new(37, -122, 34, -125)
|
87
|
+
|
88
|
+
expect(box.to_s).to eq('(37, -122, 34, -125)')
|
89
|
+
end
|
63
90
|
|
64
91
|
end
|
65
92
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: geomodel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brian Sam-Bodden
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-01-
|
11
|
+
date: 2014-01-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: geocoder
|