geospatial 1.6.0 → 1.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +2 -0
- data/lib/geospatial/box.rb +4 -0
- data/lib/geospatial/histogram.rb +69 -0
- data/lib/geospatial/location.rb +12 -0
- data/lib/geospatial/version.rb +1 -1
- data/spec/geospatial/location_spec.rb +34 -6
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 7e053b1210f1e0fa945a2e07de86aa8c211cf77e792298c849f209a73e7a34c1
|
4
|
+
data.tar.gz: bcb46dc6b66f6b532a95006ee1013df86833492bc8486bdbde7ff7c4ac088639
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ed146165687208fde777a2ef91bd523b8a1a6ab8f9c4a3691828708c08aa4e450be46b639a0c8ac1b668b131db15c87901b4739bc50d9cd66c69bdf7e80f6aec
|
7
|
+
data.tar.gz: 9c7f1051fd9f06cb87281ba32b89e8cddedbb64e735817d777220a96690ba90aae4a4ea0d851a0f86407a5a2f2e3d7ebb2d65d3cb9aadc166e62933cd927b378
|
data/README.md
CHANGED
@@ -14,6 +14,8 @@ We had a need to query a database of places efficiently using SQLite. We did som
|
|
14
14
|
|
15
15
|
After researching geospatial hashing algorithms, I found [this blog post](http://blog.notdot.net/2009/11/Damn-Cool-Algorithms-Spatial-indexing-with-Quadtrees-and-Hilbert-Curves) and decided to implement a geospatial hash using the Hilbert curve. This library exposes a fast indexing and querying mechanism based on Hilbert curves, for points on a map, which can be integrated into a database or other systems as required.
|
16
16
|
|
17
|
+
The design of this library is inspired by [Space-Filling Curves in Scala](https://github.com/cne1x/sfseize), which exposes curves as composable mathematical hash functions.
|
18
|
+
|
17
19
|
For another solution to this problem, Google uses [S2 Geometry](http://blog.christianperone.com/2015/08/googles-s2-geometry-on-the-sphere-cells-and-hilbert-curve/) which is a more specific implementation designed for geospatial indexes only.
|
18
20
|
|
19
21
|
## Installation
|
data/lib/geospatial/box.rb
CHANGED
@@ -0,0 +1,69 @@
|
|
1
|
+
#
|
2
|
+
# Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
3
|
+
#
|
4
|
+
# This file is part of the "geospatial" project and is released under the MIT license.
|
5
|
+
#
|
6
|
+
|
7
|
+
module Geospatial
|
8
|
+
# This location is specifically relating to a WGS84 coordinate on Earth.
|
9
|
+
class Histogram
|
10
|
+
def initialize(min = 0, max = 1, scale = 0.1)
|
11
|
+
@min = min
|
12
|
+
@max = max
|
13
|
+
@scale = scale
|
14
|
+
|
15
|
+
@count = ((@max - @min) / @scale).ceil
|
16
|
+
@bins = [0] * @count
|
17
|
+
@offset = 0
|
18
|
+
@scale = scale
|
19
|
+
end
|
20
|
+
|
21
|
+
attr :bins
|
22
|
+
|
23
|
+
attr :offset
|
24
|
+
attr :scale
|
25
|
+
|
26
|
+
def add(value, amount = 1)
|
27
|
+
index = ((value - @min) / @scale).floor
|
28
|
+
|
29
|
+
if @bins[index]
|
30
|
+
@bins[index] += amount
|
31
|
+
else
|
32
|
+
@bins[index] = amount
|
33
|
+
end
|
34
|
+
|
35
|
+
return self
|
36
|
+
end
|
37
|
+
|
38
|
+
def peaks
|
39
|
+
@bins.each_with_index
|
40
|
+
end
|
41
|
+
|
42
|
+
def offset(index)
|
43
|
+
@min + (index * @scale)
|
44
|
+
end
|
45
|
+
|
46
|
+
def inspect
|
47
|
+
buffer = String.new("\#<#{self.class}")
|
48
|
+
|
49
|
+
@bins.each_with_index do |bin, index|
|
50
|
+
buffer << "\n#{offset(index).to_s.rjust(8)}: #{bin}"
|
51
|
+
end
|
52
|
+
|
53
|
+
buffer << "\n>"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
class RadialHistogram < Histogram
|
58
|
+
def initialize(center, min = -180, max = 180, scale = 10)
|
59
|
+
super(min, max, scale)
|
60
|
+
|
61
|
+
@center = center
|
62
|
+
end
|
63
|
+
|
64
|
+
def add(point, value = 1)
|
65
|
+
super(point.bearing_from(@center), value)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
data/lib/geospatial/location.rb
CHANGED
@@ -158,6 +158,18 @@ module Geospatial
|
|
158
158
|
return d
|
159
159
|
end
|
160
160
|
|
161
|
+
def bearing_from(other)
|
162
|
+
lon1 = other.longitude * D2R
|
163
|
+
lat1 = other.latitude * D2R
|
164
|
+
lon2 = self.longitude * D2R
|
165
|
+
lat2 = self.latitude * D2R
|
166
|
+
|
167
|
+
return Math::atan2(
|
168
|
+
Math::sin(lon2 - lon1) * Math::cos(lat2),
|
169
|
+
Math::cos(lat1) * Math::sin(lat2) - Math::sin(lat1) * Math::cos(lat2) * Math::cos(lon2-lon1)
|
170
|
+
) * R2D
|
171
|
+
end
|
172
|
+
|
161
173
|
def - other
|
162
174
|
Distance.new(self.distance_from(other))
|
163
175
|
end
|
data/lib/geospatial/version.rb
CHANGED
@@ -21,15 +21,43 @@
|
|
21
21
|
require 'geospatial/location'
|
22
22
|
|
23
23
|
RSpec.describe Geospatial::Location do
|
24
|
-
|
25
|
-
|
24
|
+
context 'new zealand lakes' do
|
25
|
+
let(:lake_tekapo) {Geospatial::Location.new(170.53, -43.89)}
|
26
|
+
let(:lake_alex) {Geospatial::Location.new(170.45, -43.94)}
|
27
|
+
|
28
|
+
it "should compute the correct distance between two points" do
|
29
|
+
expect(lake_alex.distance_from(lake_tekapo)).to be_within(100).of(8_500)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should format nicely" do
|
33
|
+
expect("#{lake_alex}").to be == "Geospatial::Location[170.45, -43.94]"
|
34
|
+
end
|
35
|
+
end
|
26
36
|
|
27
|
-
|
28
|
-
|
37
|
+
context 'points on equator' do
|
38
|
+
let(:west) {Geospatial::Location.new(-10, 0)}
|
39
|
+
let(:east) {Geospatial::Location.new(10, 0)}
|
40
|
+
|
41
|
+
it "should compute the bearing between two points" do
|
42
|
+
expect(east.bearing_from(west)).to be_within(0.1).of(90)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should compute the bearing between two points" do
|
46
|
+
expect(west.bearing_from(east)).to be_within(0.1).of(-90)
|
47
|
+
end
|
29
48
|
end
|
30
49
|
|
31
|
-
|
32
|
-
|
50
|
+
context 'points on same latitude' do
|
51
|
+
let(:north) {Geospatial::Location.new(0, 10)}
|
52
|
+
let(:south) {Geospatial::Location.new(0, -10)}
|
53
|
+
|
54
|
+
it "should compute the bearing between two points" do
|
55
|
+
expect(north.bearing_from(south)).to be_within(0.1).of(0)
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should compute the bearing between two points" do
|
59
|
+
expect(south.bearing_from(north)).to be_within(0.1).of(180)
|
60
|
+
end
|
33
61
|
end
|
34
62
|
end
|
35
63
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: geospatial
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Samuel Williams
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-11-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -76,6 +76,7 @@ files:
|
|
76
76
|
- lib/geospatial/filter.rb
|
77
77
|
- lib/geospatial/hilbert.rb
|
78
78
|
- lib/geospatial/hilbert/curve.rb
|
79
|
+
- lib/geospatial/histogram.rb
|
79
80
|
- lib/geospatial/index.rb
|
80
81
|
- lib/geospatial/interleave.rb
|
81
82
|
- lib/geospatial/location.rb
|
@@ -119,7 +120,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
119
120
|
version: '0'
|
120
121
|
requirements: []
|
121
122
|
rubyforge_project:
|
122
|
-
rubygems_version: 2.
|
123
|
+
rubygems_version: 2.7.7
|
123
124
|
signing_key:
|
124
125
|
specification_version: 4
|
125
126
|
summary: Provides abstractions for dealing with geographical locations efficiently
|