geospatial 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2f5c7adeba4a6c4c4773d3f05ce924da0287e1b4
4
- data.tar.gz: f927b7952f48e67dd30df8c6076aa4d590d8f5cc
3
+ metadata.gz: 1958264822cca7e6426c5aada4f60e5b810f91a1
4
+ data.tar.gz: 4a76a3c348d3c75d9f557de8bc84473711d42ad5
5
5
  SHA512:
6
- metadata.gz: bb6ad414765df8a2c66706c1b157b51355b0e717fd1a9e779455bffc10c8d8a338c0f9c27171ca5023d78d5824414fe2c919be315c277380f4bebb73e6bda4c2
7
- data.tar.gz: 4f1f8d46e132ec47cbb07ee5c361b5215088e816514e254d85f40405e8fb5fa0f77fd32cc1d696f73ac0c0a424a2dd7ebc1db6f5fb4c4136a3b10dd20289990a
6
+ metadata.gz: c7961e865029758de632520c6b821bc52040b36ed443773081787fe9e6dad6afd4861a7dbd1c80db321218c03697a8994dffe03bf29da91433125d1724a741a7
7
+ data.tar.gz: 6eb65f74cad756520215e97394bfc76d8e081535a68642945062aba035963b64d2b4873600f89cdcec32de9f525f6773e5c2108273b79618299caf29503020f7
@@ -0,0 +1,80 @@
1
+ # Copyright, 2016, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ module Geospatial
22
+ # This location is specifically relating to a WGS84 coordinate on Earth.
23
+ class Distance
24
+ # Distance in meters:
25
+ def initialize(value)
26
+ @value = value
27
+ @formatted_value = nil
28
+ end
29
+
30
+ def freeze
31
+ formatted_value
32
+
33
+ super
34
+ end
35
+
36
+ UNITS = ['m', 'km'].freeze
37
+
38
+ def formatted_value
39
+ unless @formatted_value
40
+ scale = 0
41
+ value = @value
42
+
43
+ while value > 1000 and scale < UNITS.size
44
+ value /= 1000.0
45
+ scale += 1
46
+ end
47
+
48
+ @formatted_value = sprintf("%0.#{scale}f%s", value, UNITS.fetch(scale))
49
+ end
50
+
51
+ return @formatted_value
52
+ end
53
+
54
+ alias to_s formatted_value
55
+
56
+ def to_f
57
+ @value
58
+ end
59
+
60
+ def + other
61
+ Distance.new(@value + other.to_f)
62
+ end
63
+
64
+ def - other
65
+ Distance.new(@value - other.to_f)
66
+ end
67
+
68
+ def * other
69
+ Distance.new(@value * other.to_f)
70
+ end
71
+
72
+ def / other
73
+ Distance.new(@value / other.to_f)
74
+ end
75
+
76
+ def == other
77
+ @value == other.to_f
78
+ end
79
+ end
80
+ end
@@ -42,10 +42,34 @@ module Geospatial
42
42
  MIN_LATITUDE = -90.0 * D2R
43
43
  MAX_LATITUDE = 90 * D2R
44
44
  VALID_LATITUDE = MIN_LATITUDE...MAX_LATITUDE
45
-
45
+
46
+ class << self
47
+ def from_ecef(x, y, z)
48
+ # Constants (WGS ellipsoid)
49
+ a = WGS84_A
50
+ e = WGS84_E
51
+
52
+ b = Math::sqrt((a*a) * (1.0-(e*e)))
53
+ ep = Math::sqrt(((a*a)-(b*b))/(b*b))
54
+
55
+ p = Math::sqrt((x*x)+(y*y))
56
+ th = Math::atan2(a*z, b*p)
57
+
58
+ lon = Math::atan2(y, x)
59
+ lat = Math::atan2((z+ep*ep*b*(Math::sin(th) ** 3)), (p-e*e*a*(Math::cos(th)**3)))
60
+
61
+ n = a / Math::sqrt(1.0-e*e*(Math::sin(lat) ** 2))
62
+ # alt = p / Math::cos(lat)-n
63
+
64
+ return self.new(lat*R2D, lon*R2D)
65
+ end
66
+
67
+ alias [] new
68
+ end
69
+
46
70
  def initialize(longitude, latitude)
47
- @latitude = latitude
48
71
  @longitude = longitude
72
+ @latitude = latitude
49
73
  end
50
74
 
51
75
  def valid?
@@ -57,7 +81,7 @@ module Geospatial
57
81
  end
58
82
 
59
83
  def to_s
60
- "#<Location longitude=#{@longitude.to_f} latitude=#{@latitude}>"
84
+ "#{self.class}#{self.to_a}"
61
85
  end
62
86
 
63
87
  alias inspect to_s
@@ -113,34 +137,14 @@ module Geospatial
113
137
 
114
138
  return x, y, z
115
139
  end
116
-
117
- def self.from_ecef(x, y, z)
118
- # Constants (WGS ellipsoid)
119
- a = WGS84_A
120
- e = WGS84_E
121
-
122
- b = Math::sqrt((a*a) * (1.0-(e*e)))
123
- ep = Math::sqrt(((a*a)-(b*b))/(b*b))
124
-
125
- p = Math::sqrt((x*x)+(y*y))
126
- th = Math::atan2(a*z, b*p)
127
-
128
- lon = Math::atan2(y, x)
129
- lat = Math::atan2((z+ep*ep*b*(Math::sin(th) ** 3)), (p-e*e*a*(Math::cos(th)**3)))
130
-
131
- n = a / Math::sqrt(1.0-e*e*(Math::sin(lat) ** 2))
132
- # alt = p / Math::cos(lat)-n
133
-
134
- return self.new(lat*R2D, lon*R2D)
135
- end
136
140
 
137
141
  # calculate distance in metres between us and something else
138
142
  # ref: http://codingandweb.blogspot.co.nz/2012/04/calculating-distance-between-two-points.html
139
- def distance_from(other_position)
143
+ def distance_from(other)
140
144
  rlong1 = self.longitude * D2R
141
145
  rlat1 = self.latitude * D2R
142
- rlong2 = other_position.longitude * D2R
143
- rlat2 = other_position.latitude * D2R
146
+ rlong2 = other.longitude * D2R
147
+ rlat2 = other.latitude * D2R
144
148
 
145
149
  dlon = rlong1 - rlong2
146
150
  dlat = rlat1 - rlat2
@@ -151,5 +155,9 @@ module Geospatial
151
155
 
152
156
  return d
153
157
  end
158
+
159
+ def - other
160
+ Distance.new(self.distance_from(other))
161
+ end
154
162
  end
155
163
  end
@@ -44,6 +44,8 @@ module Geospatial
44
44
 
45
45
  attr :coordinates
46
46
 
47
+ alias to_a coordinates
48
+
47
49
  def eql?(other)
48
50
  self.class.eql?(other.class) and @coordinates.eql?(other.coordinates)
49
51
  end
@@ -143,6 +145,7 @@ module Geospatial
143
145
  def filter_for(region, **options)
144
146
  filter = Filter.new
145
147
 
148
+ # The filter will coalesce sequential segments of the curve into a single range.
146
149
  traverse(region, **options) do |child, prefix, order|
147
150
  filter.add(prefix, order)
148
151
  end
@@ -19,5 +19,5 @@
19
19
  # THE SOFTWARE.
20
20
 
21
21
  module Geospatial
22
- VERSION = "1.0.0"
22
+ VERSION = "1.1.0"
23
23
  end
@@ -0,0 +1,47 @@
1
+ # Copyright, 2015, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require 'geospatial/distance'
22
+
23
+ RSpec.describe Geospatial::Distance.new(10000) do
24
+ it "should have correct value" do
25
+ expect(subject.to_f).to be == 10000.0
26
+ end
27
+
28
+ it "should format string" do
29
+ expect(subject.to_s).to be == "10.0km"
30
+ end
31
+
32
+ it "can divide distances" do
33
+ expect(subject / 2).to be == 5000.0
34
+ end
35
+
36
+ it "can multiply distances" do
37
+ expect(subject * 2).to be == 20000.0
38
+ end
39
+
40
+ it "can add distances" do
41
+ expect(subject + 100).to be == 10100.0
42
+ end
43
+
44
+ it "can subtract distances" do
45
+ expect(subject - 100).to be == 9900.0
46
+ end
47
+ end
@@ -0,0 +1,55 @@
1
+
2
+ require 'geospatial/map'
3
+ require 'geospatial/polygon'
4
+
5
+ require_relative 'visualization'
6
+
7
+ RSpec.describe Geospatial::Map.for_earth(30) do
8
+ let(:ranges) {[[888899773526966272, 888899773560520703], [888899773912842240, 888899775322128383], [888899775355682816, 888899775389237247], [888899775422791680, 888899775573786623], [888899775708004352, 888899776311984127], [888899776932741120, 888899776966295551], [888899776999849984, 888899777050181631], [888899781680693248, 888899782217564159], [888899782754435072, 888899783291305983], [888899787317837824, 888899788123144191], [888899788660015104, 888899816141094911], [888899816157872128, 888899816191426559], [888899816224980992, 888899816392753151], [888899816426307584, 888899816443084799], [888899816510193664, 888899817181282303], [888899817349054464, 888899817416163327], [888899817617489920, 888899817634267135], [888899817651044352, 888899821224591359], [888899821342031872, 888899821509804031], [888899822516436992, 888899822717763583], [888899822751318016, 888899823019753471], [888900520767389696, 888900520800944127], [888900520834498560, 888900520868052991], [888900521572696064, 888900521690136575], [888900521824354304, 888900521992126463], [888900525599227904, 888900525632782335], [888900525666336768, 888900525699891199], [888900525917995008, 888900526874296319], [888900527411167232, 888900527444721663], [888900527461498880, 888900580964040703], [888900581031149568, 888900581064703999], [888900581098258432, 888900581349916671], [888900582843088896, 888900582876643327], [888900583044415488, 888900583077969919], [888900583111524352, 888900583161855999], [888900584051048448, 888900584084602879], [888900584134934528, 888900584369815551], [888900584504033280, 888900587154833407], [888900587171610624, 888900587255496703], [888900587624595456, 888900587641372671], [888900587674927104, 888900587708481535], [888900587876253696, 888900587909808127], [888900587926585344, 888900587993694207], [888900588161466368, 888900588178243583], [888900588195020800, 888900591718236159], [888900591768567808, 888900591802122239], [888900591818899456, 888900593093967871], [888900593110745088, 888900593127522303], [888900593244962816, 888900593261740031], [888900593983160320, 888900594016714751], [888900594100600832, 888900594117378047], [888900594134155264, 888900594503254015], [888900594520031232, 888900594536808447], [888900594704580608, 888900594721357823], [888900594738135040, 888900594855575551], [888900594872352768, 888900623544614911], [888900623678832640, 888900633426395135], [888900633795493888, 888900633812271103], [888900633845825536, 888900633879379967], [888900634214924288, 888900634483359743], [888900634567245824, 888900634634354687], [888900634651131904, 888900634667909119], [888900636110749696, 888900636161081343], [888900636244967424, 888900636261744639], [888900636278521856, 888900636882501631], [888900636999942144, 888900637016719359], [888900637520035840, 888900637570367487], [888900644365139968, 888900644381917183], [888900644415471616, 888900644499357695], [888900644549689344, 888900645757648895], [888900645791203328, 888900645807980543], [888900645942198272, 888900646328074239], [888900646344851456, 888900646512623615], [888900649347973120, 888900649364750335], [888900677651136512, 888900677667913727], [888900677701468160, 888900677751799807], [888900677953126400, 888900677969903615], [888912854286073856, 888912854420291583], [888912854621618176, 888912858111279103], [888912858195165184, 888912858228719615], [888912858279051264, 888912858480377855], [888912858530709504, 888912858564263935], [888912858614595584, 888912859487010815], [888912859537342464, 888912859570896895], [888912859621228544, 888912859822555135], [888912859856109568, 888912877103087615], [888912877237305344, 888912877371523071], [888912877505740800, 888912878143275007], [888912878344601600, 888912878411710463], [888912878713700352, 888912878881472511], [888912878931804160, 888912878965358591], [888912879015690240, 888912879888105471], [888912879904882688, 888912879988768767], [888912885978234880, 888912886011789311], [888912886045343744, 888912886078898175], [888912886783541248, 888912886817095679], [888912886850650112, 888912886900981759], [888912887035199488, 888912887169417215], [888912891162394624, 888912891179171839], [888912891263057920, 888912891967700991], [888912892018032640, 888912892051587071], [888912892638789632, 888912892655566847], [888912892705898496, 888912901815926783], [888912901849481216, 888912901883035647], [888912901916590080, 888912902067585023], [888912902201802752, 888912903090995199], [888912903124549632, 888912903174881279], [888912903426539520, 888912903460093951], [888912903476871168, 888912903543980031], [888912906849091584, 888912906882646015], [888912906916200448, 888912909013352447], [888912909214679040, 888912909265010687], [888912909298565120, 888912909315342335], [888912910405861376, 888912910523301887], [888912910657519616, 888912910791737343], [888912911680929792, 888912911714484223], [888912911731261440, 888912912016474111], [888912912050028544, 888912912083582975], [888912912117137408, 888913026034434047], [888913026051211264, 888913026151874559], [888913026168651776, 888913026185428991], [888913026789408768, 888913026906849279], [888913026923626496, 888913027913482239], [888913027930259456, 888913028098031615], [888913028114808832, 888913028131586047], [888913028433575936, 888913028450353151], [888913028483907584, 888913028567793663], [888913028584570880, 888913028601348095], [888913037912702976, 888913037929480191], [888913038550237184, 888913038718009343], [888913038734786560, 888913039993077759], [888913040009854976, 888913040177627135], [888913040446062592, 888913040462839807], [888913040496394240, 888913040597057535], [888913040613834752, 888913056082427903], [888913056115982336, 888913056266977279], [888913056602521600, 888913056686407679], [888913056719962112, 888913059202990079], [888913059622420480, 888913059689529343], [888913713212424192, 888913713413750783], [888913713430528000, 888913713447305215], [888913713682186240, 888913713698963455], [888913713715740672, 888913716366540799], [888913716383318016, 888913716416872447], [888913716685307904, 888913716718862335], [888913716735639552, 888913716836302847], [888913716853080064, 888913716869857279], [888913720711839744, 888913720745394175], [888913720762171392, 888913720896389119], [888913721282265088, 888913721299042303], [888913721466814464, 888913721483591679], [888913721500368896, 888913723110981631], [888913723329085440, 888913756464087039], [888913756665413632, 888913756732522495], [888913756933849088, 888913757772709887], [888913761698578432, 888913761748910079], [888913761782464512, 888913762352889855], [888913762386444288, 888913762436775935], [888913762772320256, 888913762822651903], [888913762856206336, 888913763393077247], [888913763460186112, 888913763510517759], [888913769013444608, 888913769231548415], [888913769265102848, 888913769281880063], [888913769583869952, 888913769617424383], [888913769785196544, 888913771177705471], [888913771446140928, 888913771647467519]]}
9
+
10
+ it "can generate visualisation" do
11
+ Geospatial::Visualization.for_map(subject) do |pdf, origin|
12
+ ranges.each do |(min, max)|
13
+ a = Vector.elements(subject.point_for_hash(min).to_a)
14
+ b = Vector.elements(subject.point_for_hash(max).to_a)
15
+ size = (b - a).collect(&:abs)
16
+
17
+ top_left = origin + a + Vector[0, size[1]]
18
+ pdf.rectangle(top_left.to_a, *size.to_a)
19
+ end
20
+
21
+ pdf.fill_and_stroke
22
+ end.render_file "kaikoura.pdf"
23
+ end
24
+
25
+ let(:kaikoura_polygon) {Geospatial::Polygon[
26
+ Vector[173.7218528654108, -42.32817252073923],
27
+ Vector[173.6307775307161, -42.32729039137249],
28
+ Vector[173.5400659958715, -42.39758413896335],
29
+ Vector[173.5446498680837, -42.43847509799515],
30
+ Vector[173.6833471779081, -42.44870319335309],
31
+ Vector[173.7608096128163, -42.42144813099029],
32
+ Vector[173.7218528654108, -42.32817252073923],
33
+ ]}
34
+
35
+ it "should not contain point" do
36
+ map = Geospatial::Map.for_earth(30)
37
+ filter = map.filter_for(kaikoura_polygon, depth: 12)
38
+
39
+ puts "filter.ranges.count: #{filter.ranges.count}"
40
+
41
+ #ranges.each_with_index do |(min, max), index|
42
+ # puts "#{min} -> #{max} :: #{filter.ranges[index].min} -> #{filter.ranges[index].max}"
43
+ #end
44
+
45
+ location = Geospatial::Location[176.204319, -37.660294]
46
+ point = map.point_for_object(location)
47
+
48
+ puts map.hash_for_coordinates(location.to_a)
49
+ # 888186547785722805
50
+ # 888900599658148001
51
+
52
+ expect(filter).to_not include location
53
+ end
54
+ end
55
+
@@ -25,13 +25,13 @@ require_relative 'visualization'
25
25
  RSpec.shared_context "kaikoura region" do
26
26
  let(:region) do
27
27
  Geospatial::Polygon[
28
- Vector[173.7218528654108, -42.32817252073923],
29
- Vector[173.6307775307161, -42.32729039137249],
30
- Vector[173.5400659958715, -42.39758413896335],
31
- Vector[173.5446498680837, -42.43847509799515],
32
- Vector[173.6833471779081, -42.44870319335309],
33
- Vector[173.7608096128163, -42.42144813099029],
34
- Vector[173.7218528654108, -42.32817252073923],
28
+ Vector[173.7218528654108, -42.32817252073923],
29
+ Vector[173.6307775307161, -42.32729039137249],
30
+ Vector[173.5400659958715, -42.39758413896335],
31
+ Vector[173.5446498680837, -42.43847509799515],
32
+ Vector[173.6833471779081, -42.44870319335309],
33
+ Vector[173.7608096128163, -42.42144813099029],
34
+ Vector[173.7218528654108, -42.32817252073923],
35
35
  ]
36
36
  end
37
37
 
@@ -69,8 +69,14 @@ end
69
69
  RSpec.describe Geospatial::Polygon do
70
70
  include_context "kaikoura region"
71
71
 
72
+ it "generates correct number of ranges" do
73
+ map = Geospatial::Map.for_earth(30)
74
+ filter = map.filter_for(region, depth: 12)
75
+ expect(filter.ranges.count).to be 166
76
+ end
77
+
72
78
  it "can generate visualisation" do
73
- map = Geospatial::Map.for_earth
79
+ map = Geospatial::Map.for_earth(30)
74
80
 
75
81
  map << kaikoura
76
82
 
@@ -79,16 +85,16 @@ RSpec.describe Geospatial::Polygon do
79
85
  pdf.line (origin + pa).to_a, (origin + pb).to_a
80
86
  end
81
87
 
82
- #count = 0
83
- map.traverse(region, depth: map.order - 15) do |child, prefix, order|
84
- #count += 1
88
+ count = 0
89
+ map.traverse(region, depth: 12) do |child, prefix, order|
90
+ count += 1
85
91
  size = child.size
86
92
  top_left = (origin + child.min) + Vector[0, size[1]]
87
93
  pdf.rectangle(top_left.to_a, *size.to_a)
88
94
  # puts "#{top_left.to_a} #{size.to_a}"
89
95
  end
90
96
 
91
- #puts "count=#{count}"
97
+ # puts "count=#{count}"
92
98
 
93
99
  pdf.fill_and_stroke
94
100
  end.render_file "polygon.pdf"
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.0.0
4
+ version: 1.1.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: 2016-12-27 00:00:00.000000000 Z
11
+ date: 2016-12-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -72,6 +72,7 @@ files:
72
72
  - lib/geospatial/box.rb
73
73
  - lib/geospatial/circle.rb
74
74
  - lib/geospatial/dimensions.rb
75
+ - lib/geospatial/distance.rb
75
76
  - lib/geospatial/filter.rb
76
77
  - lib/geospatial/hilbert.rb
77
78
  - lib/geospatial/hilbert/curve.rb
@@ -86,6 +87,8 @@ files:
86
87
  - spec/geospatial/box_spec.rb
87
88
  - spec/geospatial/circle_spec.rb
88
89
  - spec/geospatial/dimensions_spec.rb
90
+ - spec/geospatial/distance_spec.rb
91
+ - spec/geospatial/filter_spec.rb
89
92
  - spec/geospatial/hilbert_curve_spec.rb
90
93
  - spec/geospatial/hilbert_traverse_spec.rb
91
94
  - spec/geospatial/index_spec.rb
@@ -124,6 +127,8 @@ test_files:
124
127
  - spec/geospatial/box_spec.rb
125
128
  - spec/geospatial/circle_spec.rb
126
129
  - spec/geospatial/dimensions_spec.rb
130
+ - spec/geospatial/distance_spec.rb
131
+ - spec/geospatial/filter_spec.rb
127
132
  - spec/geospatial/hilbert_curve_spec.rb
128
133
  - spec/geospatial/hilbert_traverse_spec.rb
129
134
  - spec/geospatial/index_spec.rb