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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 91eeac2469ee68ea87e60650e5c909a25e9af3cd
4
- data.tar.gz: 712f71a592a0e803111c4380ebb78bd7a691f1e7
2
+ SHA256:
3
+ metadata.gz: 7e053b1210f1e0fa945a2e07de86aa8c211cf77e792298c849f209a73e7a34c1
4
+ data.tar.gz: bcb46dc6b66f6b532a95006ee1013df86833492bc8486bdbde7ff7c4ac088639
5
5
  SHA512:
6
- metadata.gz: 9bdb1fa1003101a6cd58be330b2730e75b7aeb64140297512ffa595f59e62874b101293b922d726b2974fe3378be002f96445fe21e582481b192fd337973ec71
7
- data.tar.gz: f67b819573274641c82c356ada6b2c58275b6f612af20117145d595aa9b73ad78f5b408809da374be98d3bead97e0d50237aa3fb107d920040f1003baa9a12ee
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
@@ -88,6 +88,10 @@ module Geospatial
88
88
  yield(Vector[@origin[0], max[1]])
89
89
  end
90
90
 
91
+ def center
92
+ @origin + (@size/2)
93
+ end
94
+
91
95
  # This yields the midpoints of the four sides of the box.
92
96
  def midpoints
93
97
  return to_enum(:midpoints) unless block_given?
@@ -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
@@ -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
@@ -19,5 +19,5 @@
19
19
  # THE SOFTWARE.
20
20
 
21
21
  module Geospatial
22
- VERSION = "1.6.0"
22
+ VERSION = "1.7.0"
23
23
  end
@@ -21,15 +21,43 @@
21
21
  require 'geospatial/location'
22
22
 
23
23
  RSpec.describe Geospatial::Location do
24
- let(:lake_tekapo) {Geospatial::Location.new(170.53, -43.89)}
25
- let(:lake_alex) {Geospatial::Location.new(170.45, -43.94)}
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
- it "compute the correct distance between two points" do
28
- expect(lake_alex.distance_from(lake_tekapo)).to be_within(100).of(8_500)
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
- it "should format nicely" do
32
- expect("#{lake_alex}").to be == "Geospatial::Location[170.45, -43.94]"
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.6.0
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: 2017-07-24 00:00:00.000000000 Z
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.6.10
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