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) ⇒ Object
Adjusts the extents of this bounding box to encompass the given object, which may be a geometry or another bounding box.
- #add_geometry(geometry) ⇒ Object
-
#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.
61 62 63 64 65 66 67 68 69 70 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 61 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.
83 84 85 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 83 def factory @factory end |
#has_m ⇒ Object (readonly)
Returns true if this bounding box tracks M coordinates.
114 115 116 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 114 def has_m @has_m end |
#has_z ⇒ Object (readonly)
Returns true if this bounding box tracks Z coordinates.
110 111 112 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 110 def has_z @has_z end |
#max_m ⇒ Object (readonly)
Returns the maximum M, or nil if this bounding box is empty.
182 183 184 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 182 def max_m @max_m end |
#max_x ⇒ Object (readonly)
Returns the maximum X, or nil if this bounding box is empty.
122 123 124 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 122 def max_x @max_x end |
#max_y ⇒ Object (readonly)
Returns the maximum Y, or nil if this bounding box is empty.
142 143 144 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 142 def max_y @max_y end |
#max_z ⇒ Object (readonly)
Returns the maximum Z, or nil if this bounding box is empty.
162 163 164 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 162 def max_z @max_z end |
#min_m ⇒ Object (readonly)
Returns the minimum M, or nil if this bounding box is empty.
178 179 180 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 178 def min_m @min_m end |
#min_x ⇒ Object (readonly)
Returns the minimum X, or nil if this bounding box is empty.
118 119 120 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 118 def min_x @min_x end |
#min_y ⇒ Object (readonly)
Returns the minimum Y, or nil if this bounding box is empty.
138 139 140 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 138 def min_y @min_y end |
#min_z ⇒ Object (readonly)
Returns the minimum Z, or nil if this bounding box is empty.
158 159 160 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 158 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.
39 40 41 42 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 39 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.
29 30 31 32 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 29 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) ⇒ Object
Adjusts the extents of this bounding box to encompass the given object, which may be a geometry or another bounding box. Returns self.
224 225 226 227 228 229 230 231 232 233 234 235 236 237 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 224 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 |
#add_geometry(geometry) ⇒ Object
353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 353 def add_geometry(geometry) 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 |
#center_m ⇒ Object
Returns the midpoint M, or nil if this bounding box is empty or has no M.
186 187 188 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 186 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.
126 127 128 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 126 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.
146 147 148 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 146 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.
166 167 168 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 166 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.
282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 282 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.
104 105 106 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 104 def degenerate? @min_x && (@min_x == @max_x || @min_y == @max_y) end |
#empty? ⇒ Boolean
Returns true if this bounding box is still empty.
87 88 89 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 87 def empty? @min_x.nil? end |
#eql?(rhs) ⇒ Boolean Also known as: ==
:nodoc:
72 73 74 75 76 77 78 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 72 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.
96 97 98 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 96 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.
192 193 194 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 192 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.
211 212 213 214 215 216 217 218 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 211 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.
199 200 201 202 203 204 205 206 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 199 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.
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 350 351 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 314 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).
244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 244 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.
132 133 134 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 132 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.
152 153 154 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 152 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.
172 173 174 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 172 def z_span @has_z ? (@max_z ? @max_z - @min_z : 0) : nil end |