Class: RGeo::Cartesian::BoundingBox
- Inherits:
-
Object
- Object
- RGeo::Cartesian::BoundingBox
- Defined in:
- lib/rgeo/cartesian/bounding_box.rb
Overview
This is a bounding box for Cartesian data. The simple cartesian implementation uses this internally to compute envelopes. You may also use it directly to compute and represent bounding boxes.
A bounding box is a set of ranges in each dimension: X, Y, as well as Z and M if supported. You can compute a bounding box for one or more geometry objects by creating a new bounding box object, and adding the geometries to it. You may then query it for the bounds, or use it to determine whether it encloses other geometries or bounding boxes.
Instance Attribute Summary collapse
-
#factory ⇒ Object
readonly
Returns the bounding box’s factory.
-
#has_m ⇒ Object
readonly
Returns true if this bounding box tracks M coordinates.
-
#has_z ⇒ Object
readonly
Returns true if this bounding box tracks Z coordinates.
-
#max_m ⇒ Object
readonly
Returns the maximum M, or nil if this bounding box is empty.
-
#max_x ⇒ Object
readonly
Returns the maximum X, or nil if this bounding box is empty.
-
#max_y ⇒ Object
readonly
Returns the maximum Y, or nil if this bounding box is empty.
-
#max_z ⇒ Object
readonly
Returns the maximum Z, or nil if this bounding box is empty.
-
#min_m ⇒ Object
readonly
Returns the minimum M, or nil if this bounding box is empty.
-
#min_x ⇒ Object
readonly
Returns the minimum X, or nil if this bounding box is empty.
-
#min_y ⇒ Object
readonly
Returns the minimum Y, or nil if this bounding box is empty.
-
#min_z ⇒ Object
readonly
Returns the minimum Z, or nil if this bounding box is empty.
Class Method Summary collapse
-
.create_from_geometry(geom_, opts_ = {}) ⇒ Object
Create a bounding box given a geometry to surround.
-
.create_from_points(point1_, point2_, opts_ = {}) ⇒ Object
Create a bounding box given two corner points.
Instance Method Summary collapse
-
#_add_geometry(geometry_) ⇒ Object
:nodoc:.
-
#_add_point(point_) ⇒ Object
:nodoc:.
-
#add(geometry_) ⇒ Object
Adjusts the extents of this bounding box to encompass the given object, which may be a geometry or another bounding box.
-
#center_m ⇒ Object
Returns the midpoint M, or nil if this bounding box is empty or has no M.
-
#center_x ⇒ Object
Returns the midpoint X, or nil if this bounding box is empty.
-
#center_y ⇒ Object
Returns the midpoint Y, or nil if this bounding box is empty.
-
#center_z ⇒ Object
Returns the midpoint Z, or nil if this bounding box is empty or has no Z.
-
#contains?(rhs_, opts_ = {}) ⇒ Boolean
Returns true if this bounding box contains the given object, which may be a geometry or another bounding box.
-
#degenerate? ⇒ Boolean
Returns true if this bounding box is degenerate.
-
#empty? ⇒ Boolean
Returns true if this bounding box is still empty.
-
#eql?(rhs_) ⇒ Boolean
(also: #==)
:nodoc:.
-
#infinitesimal? ⇒ Boolean
Returns true if this bounding box is degenerate.
-
#initialize(factory_, opts_ = {}) ⇒ BoundingBox
constructor
Create a new empty bounding box with the given factory.
-
#m_span ⇒ Object
Returns the M span, 0 if this bounding box is empty, or nil if it has no M.
-
#max_point ⇒ Object
Returns a point representing the maximum extent in all dimensions, or nil if this bounding box is empty.
-
#min_point ⇒ Object
Returns a point representing the minimum extent in all dimensions, or nil if this bounding box is empty.
-
#subdivide(opts_ = {}) ⇒ Object
Returns this bounding box subdivided, as an array of bounding boxes.
-
#to_geometry ⇒ Object
Converts this bounding box to an envelope, which will be the empty collection (if the bounding box is empty), a point (if the bounding box is not empty but both spans are 0), a line (if only one of the two spans is 0) or a polygon (if neither span is 0).
-
#x_span ⇒ Object
Returns the X span, or 0 if this bounding box is empty.
-
#y_span ⇒ Object
Returns the Y span, or 0 if this bounding box is empty.
-
#z_span ⇒ Object
Returns the Z span, 0 if this bounding box is empty, or nil if it has no Z.
Constructor Details
#initialize(factory_, opts_ = {}) ⇒ BoundingBox
Create a new empty bounding box with the given factory.
The factory defines the coordinate system for the bounding box, and also defines whether it should track Z and M coordinates. All geometries will be cast to this factory when added to this bounding box, and any generated envelope geometry will have this as its factory.
Options include:
:ignore_z
-
If true, ignore z coordinates even if the factory supports them. Default is false.
:ignore_m
-
If true, ignore m coordinates even if the factory supports them. Default is false.
59 60 61 62 63 64 65 66 67 68 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 59 def initialize(factory_, opts_ = {}) @factory = factory_ if (values_ = opts_[:raw]) @has_z, @has_m, @min_x, @max_x, @min_y, @max_y, @min_z, @max_z, @min_m, @max_m = values_ else @has_z = !opts_[:ignore_z] && factory_.property(:has_z_coordinate) ? true : false @has_m = !opts_[:ignore_m] && factory_.property(:has_m_coordinate) ? true : false @min_x = @max_x = @min_y = @max_y = @min_z = @max_z = @min_m = @max_m = nil end end |
Instance Attribute Details
#factory ⇒ Object (readonly)
Returns the bounding box’s factory.
81 82 83 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 81 def factory @factory end |
#has_m ⇒ Object (readonly)
Returns true if this bounding box tracks M coordinates.
112 113 114 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 112 def has_m @has_m end |
#has_z ⇒ Object (readonly)
Returns true if this bounding box tracks Z coordinates.
108 109 110 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 108 def has_z @has_z end |
#max_m ⇒ Object (readonly)
Returns the maximum M, or nil if this bounding box is empty.
180 181 182 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 180 def max_m @max_m end |
#max_x ⇒ Object (readonly)
Returns the maximum X, or nil if this bounding box is empty.
120 121 122 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 120 def max_x @max_x end |
#max_y ⇒ Object (readonly)
Returns the maximum Y, or nil if this bounding box is empty.
140 141 142 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 140 def max_y @max_y end |
#max_z ⇒ Object (readonly)
Returns the maximum Z, or nil if this bounding box is empty.
160 161 162 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 160 def max_z @max_z end |
#min_m ⇒ Object (readonly)
Returns the minimum M, or nil if this bounding box is empty.
176 177 178 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 176 def min_m @min_m end |
#min_x ⇒ Object (readonly)
Returns the minimum X, or nil if this bounding box is empty.
116 117 118 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 116 def min_x @min_x end |
#min_y ⇒ Object (readonly)
Returns the minimum Y, or nil if this bounding box is empty.
136 137 138 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 136 def min_y @min_y end |
#min_z ⇒ Object (readonly)
Returns the minimum Z, or nil if this bounding box is empty.
156 157 158 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 156 def min_z @min_z end |
Class Method Details
.create_from_geometry(geom_, opts_ = {}) ⇒ Object
Create a bounding box given a geometry to surround. The bounding box will be given the factory of the geometry. You may also provide the same options available to BoundingBox.new.
37 38 39 40 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 37 def self.create_from_geometry(geom_, opts_ = {}) factory_ = geom_.factory new(factory_, opts_)._add_geometry(geom_) end |
.create_from_points(point1_, point2_, opts_ = {}) ⇒ Object
Create a bounding box given two corner points. The bounding box will be given the factory of the first point. You may also provide the same options available to BoundingBox.new.
27 28 29 30 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 27 def self.create_from_points(point1_, point2_, opts_ = {}) factory_ = point1_.factory new(factory_, opts_)._add_geometry(point1_).add(point2_) end |
Instance Method Details
#_add_geometry(geometry_) ⇒ Object
:nodoc:
351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 351 def _add_geometry(geometry_) # :nodoc: case geometry_ when Feature::Point _add_point(geometry_) when Feature::LineString geometry_.points.each { |p_| _add_point(p_) } when Feature::Polygon geometry_.exterior_ring.points.each { |p_| _add_point(p_) } when Feature::MultiPoint geometry_.each { |p_| _add_point(p_) } when Feature::MultiLineString geometry_.each { |line_| line_.points.each { |p_| _add_point(p_) } } when Feature::MultiPolygon geometry_.each { |poly_| poly_.exterior_ring.points.each { |p_| _add_point(p_) } } when Feature::GeometryCollection geometry_.each { |g_| _add_geometry(g_) } end self end |
#_add_point(point_) ⇒ Object
:nodoc:
371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 371 def _add_point(point_) # :nodoc: if @min_x x_ = point_.x @min_x = x_ if x_ < @min_x @max_x = x_ if x_ > @max_x y_ = point_.y @min_y = y_ if y_ < @min_y @max_y = y_ if y_ > @max_y if @has_z z_ = point_.z @min_z = z_ if z_ < @min_z @max_z = z_ if z_ > @max_z end if @has_m m_ = point_.m @min_m = m_ if m_ < @min_m @max_m = m_ if m_ > @max_m end else @min_x = @max_x = point_.x @min_y = @max_y = point_.y @min_z = @max_z = point_.z if @has_z @min_m = @max_m = point_.m if @has_m end end |
#add(geometry_) ⇒ Object
Adjusts the extents of this bounding box to encompass the given object, which may be a geometry or another bounding box. Returns self.
222 223 224 225 226 227 228 229 230 231 232 233 234 235 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 222 def add(geometry_) case geometry_ when BoundingBox add(geometry_.min_point) add(geometry_.max_point) when Feature::Geometry if geometry_.factory == @factory _add_geometry(geometry_) else _add_geometry(Feature.cast(geometry_, @factory)) end end self end |
#center_m ⇒ Object
Returns the midpoint M, or nil if this bounding box is empty or has no M.
184 185 186 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 184 def center_m @max_m ? (@max_m + @min_m) * 0.5 : nil end |
#center_x ⇒ Object
Returns the midpoint X, or nil if this bounding box is empty.
124 125 126 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 124 def center_x @max_x ? (@max_x + @min_x) * 0.5 : nil end |
#center_y ⇒ Object
Returns the midpoint Y, or nil if this bounding box is empty.
144 145 146 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 144 def center_y @max_y ? (@max_y + @min_y) * 0.5 : nil end |
#center_z ⇒ Object
Returns the midpoint Z, or nil if this bounding box is empty or has no Z.
164 165 166 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 164 def center_z @max_z ? (@max_z + @min_z) * 0.5 : nil end |
#contains?(rhs_, opts_ = {}) ⇒ Boolean
Returns true if this bounding box contains the given object, which may be a geometry or another bounding box.
Supports these options:
:ignore_z
-
Ignore the Z coordinate when testing, even if both objects have Z. Default is false.
:ignore_m
-
Ignore the M coordinate when testing, even if both objects have M. Default is false.
280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 280 def contains?(rhs_, opts_ = {}) if Feature::Geometry === rhs_ contains?(BoundingBox.new(@factory).add(rhs_)) elsif rhs_.empty? true elsif empty? false elsif @min_x > rhs_.min_x || @max_x < rhs_.max_x || @min_y > rhs_.min_y || @max_y < rhs_.max_y false elsif @has_m && rhs_.has_m && !opts_[:ignore_m] && (@min_m > rhs_.min_m || @max_m < rhs_.max_m) false elsif @has_z && rhs_.has_z && !opts_[:ignore_z] && (@min_z > rhs_.min_z || @max_z < rhs_.max_z) false else true end end |
#degenerate? ⇒ Boolean
Returns true if this bounding box is degenerate. That is, it is nonempty but has zero area because either or both of the X or Y spans are 0.
102 103 104 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 102 def degenerate? @min_x && (@min_x == @max_x || @min_y == @max_y) end |
#empty? ⇒ Boolean
Returns true if this bounding box is still empty.
85 86 87 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 85 def empty? @min_x.nil? end |
#eql?(rhs_) ⇒ Boolean Also known as: ==
:nodoc:
70 71 72 73 74 75 76 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 70 def eql?(rhs_) # :nodoc: rhs_.is_a?(BoundingBox) && @factory == rhs_.factory && @min_x == rhs_.min_x && @max_x == rhs_.max_x && @min_y == rhs_.min_y && @max_y == rhs_.max_y && @min_z == rhs_.min_z && @max_z == rhs_.max_z && @min_m == rhs_.min_m && @max_m == rhs_.max_m end |
#infinitesimal? ⇒ Boolean
Returns true if this bounding box is degenerate. That is, it is nonempty but contains only a single point because both the X and Y spans are 0. Infinitesimal boxes are also always degenerate.
94 95 96 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 94 def infinitesimal? @min_x && @min_x == @max_x && @min_y == @max_y end |
#m_span ⇒ Object
Returns the M span, 0 if this bounding box is empty, or nil if it has no M.
190 191 192 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 190 def m_span @has_m ? (@max_m ? @max_m - @min_m : 0) : nil end |
#max_point ⇒ Object
Returns a point representing the maximum extent in all dimensions, or nil if this bounding box is empty.
209 210 211 212 213 214 215 216 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 209 def max_point if @min_x extras_ = [] extras_ << @max_z if @has_z extras_ << @max_m if @has_m @factory.point(@max_x, @max_y, *extras_) end end |
#min_point ⇒ Object
Returns a point representing the minimum extent in all dimensions, or nil if this bounding box is empty.
197 198 199 200 201 202 203 204 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 197 def min_point if @min_x extras_ = [] extras_ << @min_z if @has_z extras_ << @min_m if @has_m @factory.point(@min_x, @min_y, *extras_) end end |
#subdivide(opts_ = {}) ⇒ Object
Returns this bounding box subdivided, as an array of bounding boxes. If this bounding box is empty, returns the empty array. If this bounding box is a point, returns a one-element array containing the current point. If the x or y span is 0, bisects the line. Otherwise, generally returns a 4-1 subdivision in the X-Y plane. Does not subdivide on Z or M.
:bisect_factor
-
An optional floating point value that should be greater than 1.0. If the ratio between the larger span and the smaller span is greater than this factor, the bounding box is divided only in half instead of fourths.
312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 312 def subdivide(opts_ = {}) return [] if empty? if infinitesimal? return [ BoundingBox.new(@factory, raw: [@has_z, @has_m, @min_x, @max_x, @min_y, @max_y, @min_z, @max_z, @min_m, @max_m]) ] end factor_ = opts_[:bisect_factor] factor_ ||= 1 if degenerate? if factor_ if x_span > y_span * factor_ return [ BoundingBox.new(@factory, raw: [@has_z, @has_m, @min_x, center_x, @min_y, @max_y, @min_z, @max_z, @min_m, @max_m]), BoundingBox.new(@factory, raw: [@has_z, @has_m, center_x, @max_x, @min_y, @max_y, @min_z, @max_z, @min_m, @max_m]) ] elsif y_span > x_span * factor_ return [ BoundingBox.new(@factory, raw: [@has_z, @has_m, @min_x, @max_x, @min_y, center_y, @min_z, @max_z, @min_m, @max_m]), BoundingBox.new(@factory, raw: [@has_z, @has_m, @min_x, @max_x, center_y, @max_y, @min_z, @max_z, @min_m, @max_m]) ] end end [ BoundingBox.new(@factory, raw: [@has_z, @has_m, @min_x, center_x, @min_y, center_y, @min_z, @max_z, @min_m, @max_m]), BoundingBox.new(@factory, raw: [@has_z, @has_m, center_x, @max_x, @min_y, center_y, @min_z, @max_z, @min_m, @max_m]), BoundingBox.new(@factory, raw: [@has_z, @has_m, @min_x, center_x, center_y, @max_y, @min_z, @max_z, @min_m, @max_m]), BoundingBox.new(@factory, raw: [@has_z, @has_m, center_x, @max_x, center_y, @max_y, @min_z, @max_z, @min_m, @max_m]) ] end |
#to_geometry ⇒ Object
Converts this bounding box to an envelope, which will be the empty collection (if the bounding box is empty), a point (if the bounding box is not empty but both spans are 0), a line (if only one of the two spans is 0) or a polygon (if neither span is 0).
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 242 def to_geometry if @min_x extras_ = [] extras_ << @min_z if @has_z extras_ << @min_m if @has_m point_min_ = @factory.point(@min_x, @min_y, *extras_) if infinitesimal? point_min_ else extras_ = [] extras_ << @max_z if @has_z extras_ << @max_m if @has_m point_max_ = @factory.point(@max_x, @max_y, *extras_) if degenerate? @factory.line(point_min_, point_max_) else @factory.polygon(@factory.linear_ring([point_min_, @factory.point(@max_x, @min_y, *extras_), point_max_, @factory.point(@min_x, @max_y, *extras_), point_min_])) end end else @factory.collection([]) end end |
#x_span ⇒ Object
Returns the X span, or 0 if this bounding box is empty.
130 131 132 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 130 def x_span @max_x ? @max_x - @min_x : 0 end |
#y_span ⇒ Object
Returns the Y span, or 0 if this bounding box is empty.
150 151 152 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 150 def y_span @max_y ? @max_y - @min_y : 0 end |
#z_span ⇒ Object
Returns the Z span, 0 if this bounding box is empty, or nil if it has no Z.
170 171 172 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 170 def z_span @has_z ? (@max_z ? @max_z - @min_z : 0) : nil end |