rgeo 0.3.9 → 0.3.10
Sign up to get free protection for your applications and to get access to all the features.
- 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
|