rgeo 0.3.9 → 0.3.10
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.
- data/History.rdoc +5 -0
- data/Version +1 -1
- data/lib/rgeo/cartesian/bounding_box.rb +155 -11
- data/lib/rgeo/geographic/factory.rb +2 -1
- data/lib/rgeo/geos/ffi_classes.rb +6 -0
- data/test/common/multi_point_tests.rb +25 -0
- data/test/projected_geographic/tc_multi_point.rb +6 -0
- data/test/simple_cartesian/tc_multi_point.rb +3 -0
- data/test/simple_mercator/tc_multi_point.rb +6 -0
- data/test/spherical_geographic/tc_multi_point.rb +3 -0
- data/test/tc_cartesian_bbox.rb +53 -7
- metadata +2 -2
data/History.rdoc
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
=== 0.3.10 / 2012-04-12
|
2
|
+
|
3
|
+
* Implemented subdivision and other analysis features on Cartesian::BoundingBox.
|
4
|
+
* Operators +, -, and * were not implemented in the ffi-geos factory. Fixed.
|
5
|
+
|
1
6
|
=== 0.3.9 / 2012-04-10
|
2
7
|
|
3
8
|
* Implemented LineString#length and MultiLineString#length for simple cartesian and simple spherical factories.
|
data/Version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.3.
|
1
|
+
0.3.10
|
@@ -61,10 +61,18 @@ module RGeo
|
|
61
61
|
|
62
62
|
def self.create_from_points(point1_, point2_, opts_={})
|
63
63
|
factory_ = point1_.factory
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
64
|
+
new(factory_, opts_)._add_geometry(point1_).add(point2_)
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
# Create a bounding box given a geometry to surround.
|
69
|
+
# The bounding box will be given the factory of the geometry.
|
70
|
+
# You may also provide the same options available to
|
71
|
+
# BoundingBox.new.
|
72
|
+
|
73
|
+
def self.create_from_geometry(geom_, opts_={})
|
74
|
+
factory_ = geom_.factory
|
75
|
+
new(factory_, opts_)._add_geometry(geom_)
|
68
76
|
end
|
69
77
|
|
70
78
|
|
@@ -87,9 +95,13 @@ module RGeo
|
|
87
95
|
|
88
96
|
def initialize(factory_, opts_={})
|
89
97
|
@factory = factory_
|
90
|
-
|
91
|
-
|
92
|
-
|
98
|
+
if (values_ = opts_[:raw])
|
99
|
+
@has_z, @has_m, @min_x, @max_x, @min_y, @max_y, @min_z, @max_z, @min_m, @max_m = values_
|
100
|
+
else
|
101
|
+
@has_z = !opts_[:ignore_z] && factory_.property(:has_z_coordinate) ? true : false
|
102
|
+
@has_m = !opts_[:ignore_m] && factory_.property(:has_m_coordinate) ? true : false
|
103
|
+
@min_x = @max_x = @min_y = @max_y = @min_z = @max_z = @min_m = @max_m = nil
|
104
|
+
end
|
93
105
|
end
|
94
106
|
|
95
107
|
|
@@ -117,6 +129,25 @@ module RGeo
|
|
117
129
|
end
|
118
130
|
|
119
131
|
|
132
|
+
# Returns true if this bounding box is degenerate. That is,
|
133
|
+
# it is nonempty but contains only a single point because both
|
134
|
+
# the X and Y spans are 0. Infinitesimal boxes are also
|
135
|
+
# always degenerate.
|
136
|
+
|
137
|
+
def infinitesimal?
|
138
|
+
@min_x && @min_x == @max_x && @min_y == @max_y
|
139
|
+
end
|
140
|
+
|
141
|
+
|
142
|
+
# Returns true if this bounding box is degenerate. That is,
|
143
|
+
# it is nonempty but has zero area because either or both
|
144
|
+
# of the X or Y spans are 0.
|
145
|
+
|
146
|
+
def degenerate?
|
147
|
+
@min_x && (@min_x == @max_x || @min_y == @max_y)
|
148
|
+
end
|
149
|
+
|
150
|
+
|
120
151
|
# Returns true if this bounding box tracks Z coordinates.
|
121
152
|
|
122
153
|
def has_z
|
@@ -145,6 +176,20 @@ module RGeo
|
|
145
176
|
end
|
146
177
|
|
147
178
|
|
179
|
+
# Returns the midpoint X, or nil if this bounding box is empty.
|
180
|
+
|
181
|
+
def center_x
|
182
|
+
@max_x ? (@max_x + @min_x) * 0.5 : nil
|
183
|
+
end
|
184
|
+
|
185
|
+
|
186
|
+
# Returns the X span, or 0 if this bounding box is empty.
|
187
|
+
|
188
|
+
def x_span
|
189
|
+
@max_x ? @max_x - @min_x : 0
|
190
|
+
end
|
191
|
+
|
192
|
+
|
148
193
|
# Returns the minimum Y, or nil if this bounding box is empty.
|
149
194
|
|
150
195
|
def min_y
|
@@ -159,6 +204,20 @@ module RGeo
|
|
159
204
|
end
|
160
205
|
|
161
206
|
|
207
|
+
# Returns the midpoint Y, or nil if this bounding box is empty.
|
208
|
+
|
209
|
+
def center_y
|
210
|
+
@max_y ? (@max_y + @min_y) * 0.5 : nil
|
211
|
+
end
|
212
|
+
|
213
|
+
|
214
|
+
# Returns the Y span, or 0 if this bounding box is empty.
|
215
|
+
|
216
|
+
def y_span
|
217
|
+
@max_y ? @max_y - @min_y : 0
|
218
|
+
end
|
219
|
+
|
220
|
+
|
162
221
|
# Returns the minimum Z, or nil if this bounding box is empty.
|
163
222
|
|
164
223
|
def min_z
|
@@ -173,6 +232,20 @@ module RGeo
|
|
173
232
|
end
|
174
233
|
|
175
234
|
|
235
|
+
# Returns the midpoint Z, or nil if this bounding box is empty or has no Z.
|
236
|
+
|
237
|
+
def center_z
|
238
|
+
@max_z ? (@max_z + @min_z) * 0.5 : nil
|
239
|
+
end
|
240
|
+
|
241
|
+
|
242
|
+
# Returns the Z span, 0 if this bounding box is empty, or nil if it has no Z.
|
243
|
+
|
244
|
+
def z_span
|
245
|
+
@has_z ? (@max_z ? @max_z - @min_z : 0) : nil
|
246
|
+
end
|
247
|
+
|
248
|
+
|
176
249
|
# Returns the minimum M, or nil if this bounding box is empty.
|
177
250
|
|
178
251
|
def min_m
|
@@ -187,6 +260,20 @@ module RGeo
|
|
187
260
|
end
|
188
261
|
|
189
262
|
|
263
|
+
# Returns the midpoint M, or nil if this bounding box is empty or has no M.
|
264
|
+
|
265
|
+
def center_m
|
266
|
+
@max_m ? (@max_m + @min_m) * 0.5 : nil
|
267
|
+
end
|
268
|
+
|
269
|
+
|
270
|
+
# Returns the M span, 0 if this bounding box is empty, or nil if it has no M.
|
271
|
+
|
272
|
+
def m_span
|
273
|
+
@has_m ? (@max_m ? @max_m - @min_m : 0) : nil
|
274
|
+
end
|
275
|
+
|
276
|
+
|
190
277
|
# Returns a point representing the minimum extent in all dimensions,
|
191
278
|
# or nil if this bounding box is empty.
|
192
279
|
|
@@ -237,8 +324,10 @@ module RGeo
|
|
237
324
|
end
|
238
325
|
|
239
326
|
|
240
|
-
# Converts this bounding box to an envelope
|
241
|
-
#
|
327
|
+
# Converts this bounding box to an envelope, which will be the
|
328
|
+
# empty collection (if the bounding box is empty), a point (if the
|
329
|
+
# bounding box is not empty but both spans are 0), a line (if only
|
330
|
+
# one of the two spans is 0) or a polygon (if neither span is 0).
|
242
331
|
|
243
332
|
def to_geometry
|
244
333
|
if @min_x
|
@@ -246,14 +335,14 @@ module RGeo
|
|
246
335
|
extras_ << @min_z if @has_z
|
247
336
|
extras_ << @min_m if @has_m
|
248
337
|
point_min_ = @factory.point(@min_x, @min_y, *extras_)
|
249
|
-
if
|
338
|
+
if infinitesimal?
|
250
339
|
point_min_
|
251
340
|
else
|
252
341
|
extras_ = []
|
253
342
|
extras_ << @max_z if @has_z
|
254
343
|
extras_ << @max_m if @has_m
|
255
344
|
point_max_ = @factory.point(@max_x, @max_y, *extras_)
|
256
|
-
if
|
345
|
+
if degenerate?
|
257
346
|
@factory.line(point_min_, point_max_)
|
258
347
|
else
|
259
348
|
@factory.polygon(@factory.linear_ring([point_min_,
|
@@ -298,6 +387,60 @@ module RGeo
|
|
298
387
|
end
|
299
388
|
|
300
389
|
|
390
|
+
# Returns this bounding box subdivided, as an array of bounding boxes.
|
391
|
+
# If this bounding box is empty, returns the empty array.
|
392
|
+
# If this bounding box is a point, returns a one-element array
|
393
|
+
# containing the current point.
|
394
|
+
# If the x or y span is 0, bisects the line.
|
395
|
+
# Otherwise, generally returns a 4-1 subdivision in the X-Y plane.
|
396
|
+
# Does not subdivide on Z or M.
|
397
|
+
#
|
398
|
+
# [<tt>:bisect_factor</tt>]
|
399
|
+
# An optional floating point value that should be greater than 1.0.
|
400
|
+
# If the ratio between the larger span and the smaller span is
|
401
|
+
# greater than this factor, the bounding box is divided only in
|
402
|
+
# half instead of fourths.
|
403
|
+
|
404
|
+
def subdivide(opts_={})
|
405
|
+
return [] if empty?
|
406
|
+
if infinitesimal?
|
407
|
+
return [
|
408
|
+
BoundingBox.new(@factory, :raw => [@has_z, @has_m,
|
409
|
+
@min_x, @max_x, @min_y, @max_y, @min_z, @max_z, @min_m, @max_m])
|
410
|
+
]
|
411
|
+
end
|
412
|
+
factor_ = opts_[:bisect_factor]
|
413
|
+
factor_ ||= 1 if degenerate?
|
414
|
+
if factor_
|
415
|
+
if x_span > y_span * factor_
|
416
|
+
return [
|
417
|
+
BoundingBox.new(@factory, :raw => [@has_z, @has_m,
|
418
|
+
@min_x, center_x, @min_y, @max_y, @min_z, @max_z, @min_m, @max_m]),
|
419
|
+
BoundingBox.new(@factory, :raw => [@has_z, @has_m,
|
420
|
+
center_x, @max_x, @min_y, @max_y, @min_z, @max_z, @min_m, @max_m])
|
421
|
+
]
|
422
|
+
elsif y_span > x_span * factor_
|
423
|
+
return [
|
424
|
+
BoundingBox.new(@factory, :raw => [@has_z, @has_m,
|
425
|
+
@min_x, @max_x, @min_y, center_y, @min_z, @max_z, @min_m, @max_m]),
|
426
|
+
BoundingBox.new(@factory, :raw => [@has_z, @has_m,
|
427
|
+
@min_x, @max_x, center_y, @max_y, @min_z, @max_z, @min_m, @max_m])
|
428
|
+
]
|
429
|
+
end
|
430
|
+
end
|
431
|
+
[
|
432
|
+
BoundingBox.new(@factory, :raw => [@has_z, @has_m,
|
433
|
+
@min_x, center_x, @min_y, center_y, @min_z, @max_z, @min_m, @max_m]),
|
434
|
+
BoundingBox.new(@factory, :raw => [@has_z, @has_m,
|
435
|
+
center_x, @max_x, @min_y, center_y, @min_z, @max_z, @min_m, @max_m]),
|
436
|
+
BoundingBox.new(@factory, :raw => [@has_z, @has_m,
|
437
|
+
@min_x, center_x, center_y, @max_y, @min_z, @max_z, @min_m, @max_m]),
|
438
|
+
BoundingBox.new(@factory, :raw => [@has_z, @has_m,
|
439
|
+
center_x, @max_x, center_y, @max_y, @min_z, @max_z, @min_m, @max_m])
|
440
|
+
]
|
441
|
+
end
|
442
|
+
|
443
|
+
|
301
444
|
def _add_geometry(geometry_) # :nodoc:
|
302
445
|
case geometry_
|
303
446
|
when Feature::Point
|
@@ -315,6 +458,7 @@ module RGeo
|
|
315
458
|
when Feature::GeometryCollection
|
316
459
|
geometry_.each{ |g_| _add_geometry(g_) }
|
317
460
|
end
|
461
|
+
self
|
318
462
|
end
|
319
463
|
|
320
464
|
|
@@ -273,7 +273,7 @@ module RGeo
|
|
273
273
|
# this factory.
|
274
274
|
|
275
275
|
def project(geometry_)
|
276
|
-
return nil unless @projector
|
276
|
+
return nil unless @projector && geometry_
|
277
277
|
unless geometry_.factory == self
|
278
278
|
raise Error::InvalidGeometry, 'Wrong geometry type'
|
279
279
|
end
|
@@ -287,6 +287,7 @@ module RGeo
|
|
287
287
|
# the projection defined by this factory.
|
288
288
|
|
289
289
|
def unproject(geometry_)
|
290
|
+
return nil unless geometry_
|
290
291
|
unless @projector && @projector.projection_factory == geometry_.factory
|
291
292
|
raise Error::InvalidGeometry, 'You can unproject only features that are in the projected coordinate space.'
|
292
293
|
end
|
@@ -300,18 +300,24 @@ module RGeo
|
|
300
300
|
fg_ ? @factory.wrap_fg_geom(@fg_geom.intersection(fg_)) : nil
|
301
301
|
end
|
302
302
|
|
303
|
+
alias_method :*, :intersection
|
304
|
+
|
303
305
|
|
304
306
|
def union(rhs_)
|
305
307
|
fg_ = factory._convert_to_fg_geometry(rhs_)
|
306
308
|
fg_ ? @factory.wrap_fg_geom(@fg_geom.union(fg_)) : nil
|
307
309
|
end
|
308
310
|
|
311
|
+
alias_method :+, :union
|
312
|
+
|
309
313
|
|
310
314
|
def difference(rhs_)
|
311
315
|
fg_ = factory._convert_to_fg_geometry(rhs_)
|
312
316
|
fg_ ? @factory.wrap_fg_geom(@fg_geom.difference(fg_)) : nil
|
313
317
|
end
|
314
318
|
|
319
|
+
alias_method :-, :difference
|
320
|
+
|
315
321
|
|
316
322
|
def sym_difference(rhs_)
|
317
323
|
fg_ = factory._convert_to_fg_geometry(rhs_)
|
@@ -202,6 +202,31 @@ module RGeo
|
|
202
202
|
end
|
203
203
|
|
204
204
|
|
205
|
+
def test_union
|
206
|
+
geom1_ = @factory.multi_point([@point1, @point2])
|
207
|
+
geom2_ = @factory.multi_point([@point1, @point3])
|
208
|
+
geom3_ = @factory.multi_point([@point1, @point2, @point3])
|
209
|
+
assert_equal(geom3_, geom1_.union(geom2_))
|
210
|
+
assert_equal(geom3_, geom1_ + geom2_)
|
211
|
+
end
|
212
|
+
|
213
|
+
|
214
|
+
def test_difference
|
215
|
+
geom1_ = @factory.multi_point([@point1, @point2])
|
216
|
+
geom2_ = @factory.multi_point([@point1, @point3])
|
217
|
+
assert_equal(@point2, geom1_.difference(geom2_))
|
218
|
+
assert_equal(@point2, geom1_ - geom2_)
|
219
|
+
end
|
220
|
+
|
221
|
+
|
222
|
+
def test_intersection
|
223
|
+
geom1_ = @factory.multi_point([@point1, @point2])
|
224
|
+
geom2_ = @factory.multi_point([@point1, @point3])
|
225
|
+
assert_equal(@point1, geom1_.intersection(geom2_))
|
226
|
+
assert_equal(@point1, geom1_ * geom2_)
|
227
|
+
end
|
228
|
+
|
229
|
+
|
205
230
|
end
|
206
231
|
|
207
232
|
end
|
data/test/tc_cartesian_bbox.rb
CHANGED
@@ -59,27 +59,35 @@ module RGeo
|
|
59
59
|
assert_equal(true, bbox_.to_geometry.is_empty?)
|
60
60
|
assert_equal(true, bbox_.contains?(bbox_))
|
61
61
|
assert_equal(false, bbox_.contains?(@factory.point(1, 1)))
|
62
|
+
assert_nil(bbox_.center_x)
|
63
|
+
assert_equal(0, bbox_.x_span)
|
64
|
+
assert_equal(0, bbox_.subdivide.size)
|
62
65
|
end
|
63
66
|
|
64
67
|
|
65
68
|
def test_point_bbox
|
66
69
|
empty_bbox_ = ::RGeo::Cartesian::BoundingBox.new(@factory)
|
67
70
|
bbox_ = ::RGeo::Cartesian::BoundingBox.new(@factory)
|
68
|
-
bbox_.add(@factory.point(1,
|
71
|
+
bbox_.add(@factory.point(1, 2))
|
69
72
|
assert_equal(false, bbox_.empty?)
|
70
73
|
assert_equal(false, bbox_.has_z)
|
71
74
|
assert_equal(1.0, bbox_.min_x)
|
72
|
-
assert_equal(
|
75
|
+
assert_equal(2.0, bbox_.min_y)
|
73
76
|
assert_equal(1.0, bbox_.max_x)
|
74
|
-
assert_equal(
|
77
|
+
assert_equal(2.0, bbox_.max_y)
|
75
78
|
assert_equal(@factory, bbox_.factory)
|
76
|
-
assert_equal(@factory.point(1,
|
77
|
-
assert_equal(@factory.point(1,
|
78
|
-
assert_equal(@factory.point(1,
|
79
|
+
assert_equal(@factory.point(1, 2), bbox_.min_point)
|
80
|
+
assert_equal(@factory.point(1, 2), bbox_.max_point)
|
81
|
+
assert_equal(@factory.point(1, 2), bbox_.to_geometry)
|
79
82
|
assert_equal(true, bbox_.contains?(empty_bbox_))
|
80
83
|
assert_equal(false, empty_bbox_.contains?(bbox_))
|
81
|
-
assert_equal(true, bbox_.contains?(@factory.point(1,
|
84
|
+
assert_equal(true, bbox_.contains?(@factory.point(1, 2)))
|
82
85
|
assert_equal(false, bbox_.contains?(@factory.point(2, 1)))
|
86
|
+
assert_equal(1, bbox_.center_x)
|
87
|
+
assert_equal(0, bbox_.x_span)
|
88
|
+
assert_equal(2, bbox_.center_y)
|
89
|
+
assert_equal(0, bbox_.y_span)
|
90
|
+
assert_equal([bbox_], bbox_.subdivide)
|
83
91
|
end
|
84
92
|
|
85
93
|
|
@@ -102,6 +110,10 @@ module RGeo
|
|
102
110
|
assert_equal(false, empty_bbox_.contains?(bbox_))
|
103
111
|
assert_equal(true, bbox_.contains?(@factory.point(1, 3)))
|
104
112
|
assert_equal(false, bbox_.contains?(@factory.point(2, 1)))
|
113
|
+
assert_equal(1.5, bbox_.center_x)
|
114
|
+
assert_equal(1, bbox_.x_span)
|
115
|
+
assert_equal(3.5, bbox_.center_y)
|
116
|
+
assert_equal(1, bbox_.y_span)
|
105
117
|
end
|
106
118
|
|
107
119
|
|
@@ -115,6 +127,40 @@ module RGeo
|
|
115
127
|
end
|
116
128
|
|
117
129
|
|
130
|
+
def test_basic_rect_subdivide
|
131
|
+
bbox_ = ::RGeo::Cartesian::BoundingBox.new(@factory)
|
132
|
+
bbox_.add(@factory.point(1, 2))
|
133
|
+
bbox_.add(@factory.point(5, 4))
|
134
|
+
quads_ = bbox_.subdivide
|
135
|
+
quads_.each{ |q_| assert_equal(2.0, q_.to_geometry.area) }
|
136
|
+
quadsum_ = quads_[0].to_geometry + quads_[1].to_geometry +
|
137
|
+
quads_[2].to_geometry + quads_[3].to_geometry
|
138
|
+
assert_equal(bbox_.to_geometry, quadsum_)
|
139
|
+
end
|
140
|
+
|
141
|
+
|
142
|
+
def test_horiz_line_subdivide
|
143
|
+
bbox_ = ::RGeo::Cartesian::BoundingBox.new(@factory)
|
144
|
+
bbox_.add(@factory.point(1, 2))
|
145
|
+
bbox_.add(@factory.point(5, 2))
|
146
|
+
lines_ = bbox_.subdivide
|
147
|
+
lines_.each{ |line_| assert_equal(2.0, line_.to_geometry.length) }
|
148
|
+
linesum_ = lines_[0].to_geometry + lines_[1].to_geometry
|
149
|
+
assert_equal(bbox_.to_geometry, linesum_)
|
150
|
+
end
|
151
|
+
|
152
|
+
|
153
|
+
def test_vert_line_subdivide
|
154
|
+
bbox_ = ::RGeo::Cartesian::BoundingBox.new(@factory)
|
155
|
+
bbox_.add(@factory.point(1, 2))
|
156
|
+
bbox_.add(@factory.point(1, 6))
|
157
|
+
lines_ = bbox_.subdivide
|
158
|
+
lines_.each{ |line_| assert_equal(2.0, line_.to_geometry.length) }
|
159
|
+
linesum_ = lines_[0].to_geometry + lines_[1].to_geometry
|
160
|
+
assert_equal(bbox_.to_geometry, linesum_)
|
161
|
+
end
|
162
|
+
|
163
|
+
|
118
164
|
end
|
119
165
|
|
120
166
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rgeo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.10
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-04-
|
12
|
+
date: 2012-04-13 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: RGeo is a geospatial data library for Ruby. It provides an implementation
|
15
15
|
of the Open Geospatial Consortium's Simple Features Specification, used by most
|