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?(other) ⇒ 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.
93 94 95 96 97 98 99 100 101 102 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 93 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.
24 25 26 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 24 def factory @factory end |
#has_m ⇒ Object (readonly)
Returns true if this bounding box tracks M coordinates.
30 31 32 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 30 def has_m @has_m end |
#has_z ⇒ Object (readonly)
Returns true if this bounding box tracks Z coordinates.
27 28 29 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 27 def has_z @has_z end |
#max_m ⇒ Object (readonly)
Returns the maximum M, or nil if this bounding box is empty.
54 55 56 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 54 def max_m @max_m end |
#max_x ⇒ Object (readonly)
Returns the maximum X, or nil if this bounding box is empty.
36 37 38 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 36 def max_x @max_x end |
#max_y ⇒ Object (readonly)
Returns the maximum Y, or nil if this bounding box is empty.
42 43 44 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 42 def max_y @max_y end |
#max_z ⇒ Object (readonly)
Returns the maximum Z, or nil if this bounding box is empty.
48 49 50 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 48 def max_z @max_z end |
#min_m ⇒ Object (readonly)
Returns the minimum M, or nil if this bounding box is empty.
51 52 53 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 51 def min_m @min_m end |
#min_x ⇒ Object (readonly)
Returns the minimum X, or nil if this bounding box is empty.
33 34 35 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 33 def min_x @min_x end |
#min_y ⇒ Object (readonly)
Returns the minimum Y, or nil if this bounding box is empty.
39 40 41 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 39 def min_y @min_y end |
#min_z ⇒ Object (readonly)
Returns the minimum Z, or nil if this bounding box is empty.
45 46 47 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 45 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.
71 72 73 74 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 71 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.
61 62 63 64 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 61 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.
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 |
#add_geometry(geometry) ⇒ Object
348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 348 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.
178 179 180 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 178 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.
138 139 140 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 138 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.
150 151 152 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 150 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.
162 163 164 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 162 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 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 280 def contains?(rhs, opts = {}) return contains?(BoundingBox.new(@factory).add(rhs)) if Feature::Geometry === rhs return true if rhs.empty? return false if empty? cmp_xymz = (@min_x > rhs.min_x || @max_x < rhs.max_x || @min_y > rhs.min_y || @max_y < rhs.max_y) || (@has_m && rhs.has_m && !opts[:ignore_m] && (@min_m > rhs.min_m || @max_m < rhs.max_m)) || (@has_z && rhs.has_z && !opts[:ignore_z] && (@min_z > rhs.min_z || @max_z < rhs.max_z)) !cmp_xymz 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.
132 133 134 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 132 def degenerate? @min_x && (@min_x == @max_x || @min_y == @max_y) end |
#empty? ⇒ Boolean
Returns true if this bounding box is still empty.
115 116 117 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 115 def empty? @min_x.nil? end |
#eql?(other) ⇒ Boolean Also known as: ==
:nodoc:
104 105 106 107 108 109 110 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 104 def eql?(other) # :nodoc: other.is_a?(BoundingBox) && @factory == other.factory && @min_x == other.min_x && @max_x == other.max_x && @min_y == other.min_y && @max_y == other.max_y && @min_z == other.min_z && @max_z == other.max_z && @min_m == other.min_m && @max_m == other.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.
124 125 126 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 124 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.
184 185 186 187 188 189 190 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 184 def m_span return unless @has_m return 0 unless @max_m @max_m - @min_m end |
#max_point ⇒ Object
Returns a point representing the maximum extent in all dimensions, or nil if this bounding box is empty.
208 209 210 211 212 213 214 215 216 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 208 def max_point return unless @min_x extras = [] extras << @max_z if @has_z extras << @max_m if @has_m @factory.point(@max_x, @max_y, *extras) end |
#min_point ⇒ Object
Returns a point representing the minimum extent in all dimensions, or nil if this bounding box is empty.
195 196 197 198 199 200 201 202 203 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 195 def min_point return unless @min_x extras = [] extras << @min_z if @has_z extras << @min_m if @has_m @factory.point(@min_x, @min_y, *extras) 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.
309 310 311 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 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 309 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.
144 145 146 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 144 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.
156 157 158 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 156 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.
168 169 170 171 172 173 174 |
# File 'lib/rgeo/cartesian/bounding_box.rb', line 168 def z_span return unless @has_z return 0 unless @max_z @max_z - @min_z end |