geospatial 1.6.0 → 1.7.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 +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
|