geospatial 1.13.0 → 1.14.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
2
  SHA256:
3
- metadata.gz: 7192e26af8621237a3727ebdc875df7af056a4ac9bf36dcadba378107c97b6a4
4
- data.tar.gz: 833732089ee04ebedaf970430661cb51ec85fc878b1093d9b71440cf8a347327
3
+ metadata.gz: 6ef4b5ff93a87b5fb2733e6bbbe587be842c11ba2365131be98760bb66ee7143
4
+ data.tar.gz: 8468357c04f732b2a843ef154b7e93b8732dc334b9e76da989f22428b3eb18bf
5
5
  SHA512:
6
- metadata.gz: ea63ff5c6dfa08038b891f2df6e3d0e78a77151834a9655a8f8dee85eca08d603860c99566f8d47b1ce0d45d60bd42fa2d09da187884f92e1ee637a21e7aef2c
7
- data.tar.gz: 1c28ff01ced07bddb5091eea5aeadce0ebf4772752d3317a55ba3fcb8605b49573fb186b2dd27334930b0cffa5dfec5caf851c47aeb3468b1984bd401872f754
6
+ metadata.gz: 3c97d956c5ef2b8b959d85f4ce07877020000b0d24ba5496edf82ef824b3d23c7c7f9471e5e48ae53f9524aab2703dd11449dc476d7288a7d91a0c7fb58e8c13
7
+ data.tar.gz: 368fc193f939b360aa1945198c054aa7bf0f05620d1307b95a0ed89f1a09a374b605c2baecc3244e2ba81bc0fe70546ff357e705d3e423d3543163cf64394a89
@@ -202,5 +202,20 @@ module Geospatial
202
202
  def - other
203
203
  Distance.new(self.distance_from(other))
204
204
  end
205
+
206
+ # Compute count midpoints between self and other.
207
+ # @param count [Integer] the number of segments to generate.
208
+ def midpoints_to(other, count)
209
+ return to_enum(:midpoints_to, other, count) unless block_given?
210
+
211
+ distance = other.distance_from(self)
212
+ bearing = other.bearing_from(self)
213
+
214
+ step = distance / count
215
+
216
+ (1...count).each do |i|
217
+ yield self.location_by(bearing, step * i)
218
+ end
219
+ end
205
220
  end
206
221
  end
@@ -95,10 +95,12 @@ module Geospatial
95
95
  end
96
96
  end
97
97
 
98
- def simplify(minimum_distance = 1)
98
+ def simplify
99
99
  simplified_points = @points.first(1)
100
100
 
101
- @points.each_with_index do |point, index|
101
+ (1...@points.size).each do |index|
102
+ point = @points[index]
103
+
102
104
  next_point = @points[(index+1) % @points.size]
103
105
 
104
106
  if yield(simplified_points.last, point, next_point)
@@ -109,6 +111,34 @@ module Geospatial
109
111
  self.class.new(simplified_points, bounding_box)
110
112
  end
111
113
 
114
+ # @example
115
+ # polygon.subdivide do |a, b|
116
+ # a = Geospatial::Location.new(*a)
117
+ # b = Geospatial::Location.new(*b)
118
+ # if a.distance_from(b) > maximum_distance
119
+ # a.midpoints(b, 2)
120
+ # end
121
+ # end
122
+ def subdivide
123
+ simplified_points = @points.first(1)
124
+
125
+ (1..@points.size).each do |index|
126
+ point = @points[index % @points.size]
127
+ next_point = @points[(index+1) % @points.size]
128
+
129
+ if points = yield(simplified_points.last, point, next_point)
130
+ simplified_points.concat(points)
131
+ end
132
+
133
+ # Polygons are represented by a closed sequence of points, but we need to subdivide by the last point at the first point too. However, we don't add the first point a 2nd time.
134
+ if index < @points.size
135
+ simplified_points << point
136
+ end
137
+ end
138
+
139
+ self.class.new(simplified_points, bounding_box)
140
+ end
141
+
112
142
  def self.is_left(p0, p1, p2)
113
143
  a = p1 - p0
114
144
  b = p2 - p0
@@ -19,5 +19,5 @@
19
19
  # THE SOFTWARE.
20
20
 
21
21
  module Geospatial
22
- VERSION = "1.13.0"
22
+ VERSION = "1.14.0"
23
23
  end
@@ -69,6 +69,29 @@ RSpec.describe Geospatial::Location do
69
69
  expect(south.bearing_from(north)).to be_within(0.1).of(180)
70
70
  end
71
71
  end
72
+
73
+ describe '#midpoints_to' do
74
+ let(:north) {Geospatial::Location.new(10, 10)}
75
+ let(:south) {Geospatial::Location.new(-10, -10)}
76
+
77
+ it "can generate one midpoint" do
78
+ midpoints = north.midpoints_to(south, 4).to_a
79
+
80
+ expect(midpoints.size).to be == 3
81
+
82
+ expect(midpoints[0].distance_from(
83
+ Geospatial::Location.new(4.9616, 5.0190)
84
+ )).to be < 10
85
+
86
+ expect(midpoints[1].distance_from(
87
+ Geospatial::Location.new(0, 0)
88
+ )).to be < 10
89
+
90
+ expect(midpoints[2].distance_from(
91
+ Geospatial::Location.new(-4.9616, -5.0190)
92
+ )).to be < 10
93
+ end
94
+ end
72
95
  end
73
96
 
74
97
  require 'bigdecimal'
@@ -105,28 +105,49 @@ RSpec.describe Geospatial::Polygon do
105
105
  end
106
106
  end
107
107
 
108
- RSpec.shared_context "visualize polygon" do
108
+ RSpec.shared_context "visualize polygon" do |depth = 12|
109
109
  it "can generate visualisation" do
110
110
  map = Geospatial::Map.for_earth(30)
111
111
 
112
112
  coordinates = region_string.split(/\s+/).collect{|coordinate| Vector.elements(coordinate.split(',').collect(&:to_f).first(2))}
113
113
  region = Geospatial::Polygon.new(coordinates)
114
114
 
115
+ maximum_distance = 100_000
116
+
117
+ region = region.subdivide do |a, b|
118
+ a = Geospatial::Location.new(*a)
119
+ b = Geospatial::Location.new(*b)
120
+
121
+ distance = a.distance_from(b)
122
+
123
+ if distance > maximum_distance
124
+ a.midpoints_to(b, (distance / maximum_distance).ceil).map{|p| Vector[*p]}
125
+ end
126
+ end
127
+
115
128
  Geospatial::Visualization.for_map(map) do |pdf, origin|
116
129
  region.edges do |pa, pb|
117
130
  pdf.line (origin + pa).to_a, (origin + pb).to_a
118
131
  end
119
132
 
120
133
  count = 0
121
- map.traverse(region, depth: 12) do |child, prefix, order|
134
+ map.traverse(region, depth: depth) do |child, prefix, order|
122
135
  count += 1
123
136
  size = child.size
124
137
  top_left = (origin + child.min) + Vector[0, size[1]]
125
138
  pdf.rectangle(top_left.to_a, *size.to_a)
126
- # puts "#{top_left.to_a} #{size.to_a}"
139
+ # $stderr.puts "#{top_left.to_a} #{size.to_a}"
127
140
  end
128
141
 
129
- # puts "count=#{count}"
142
+ # $stderr.puts "count=#{count}"
143
+
144
+ pdf.fill_and_stroke
145
+
146
+ pdf.fill_color 'aaaaff'
147
+
148
+ region.points.each do |p|
149
+ pdf.fill_circle((origin + p).to_a, 0.01)
150
+ end
130
151
 
131
152
  pdf.fill_and_stroke
132
153
  end.render_file "#{self.class.description}.pdf"
@@ -144,3 +165,10 @@ RSpec.describe "Whanganui Polygon" do
144
165
 
145
166
  include_context "visualize polygon"
146
167
  end
168
+
169
+
170
+ RSpec.describe "New Zealand Bounding Box" do
171
+ let(:region_string) {"165.7930426042,-47.8671059558 179.1461410947,-47.8671059558 179.1461410947,-33.4566032676 165.7930426042,-33.4566032676"}
172
+
173
+ include_context "visualize polygon", 20
174
+ end
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.13.0
4
+ version: 1.14.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: 2019-08-02 00:00:00.000000000 Z
11
+ date: 2019-09-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: covered