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.
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 ::new.
# File lib/rgeo/cartesian/bounding_box.rb, line 73 def self.create_from_geometry(geom_, opts_={}) factory_ = geom_.factory new(factory_, opts_)._add_geometry(geom_) end
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 ::new.
# File lib/rgeo/cartesian/bounding_box.rb, line 62 def self.create_from_points(point1_, point2_, opts_={}) factory_ = point1_.factory new(factory_, opts_)._add_geometry(point1_).add(point2_) end
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.
# File lib/rgeo/cartesian/bounding_box.rb, line 96 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
Adjusts the extents of this bounding box to encompass the given object, which may be a geometry or another bounding box. Returns self.
# File lib/rgeo/cartesian/bounding_box.rb, line 311 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
Returns the midpoint M, or nil if this bounding box is empty or has no M.
# File lib/rgeo/cartesian/bounding_box.rb, line 265 def center_m @max_m ? (@max_m + @min_m) * 0.5 : nil end
Returns the midpoint X, or nil if this bounding box is empty.
# File lib/rgeo/cartesian/bounding_box.rb, line 181 def center_x @max_x ? (@max_x + @min_x) * 0.5 : nil end
Returns the midpoint Y, or nil if this bounding box is empty.
# File lib/rgeo/cartesian/bounding_box.rb, line 209 def center_y @max_y ? (@max_y + @min_y) * 0.5 : nil end
Returns the midpoint Z, or nil if this bounding box is empty or has no Z.
# File lib/rgeo/cartesian/bounding_box.rb, line 237 def center_z @max_z ? (@max_z + @min_z) * 0.5 : nil end
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.
# File lib/rgeo/cartesian/bounding_box.rb, line 371 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
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.
# File lib/rgeo/cartesian/bounding_box.rb, line 146 def degenerate? @min_x && (@min_x == @max_x || @min_y == @max_y) end
Returns true if this bounding box is still empty.
# File lib/rgeo/cartesian/bounding_box.rb, line 127 def empty? @min_x.nil? end
Returns the bounding box’s factory.
# File lib/rgeo/cartesian/bounding_box.rb, line 120 def factory @factory end
Returns true if this bounding box tracks M coordinates.
# File lib/rgeo/cartesian/bounding_box.rb, line 160 def has_m @has_m end
Returns true if this bounding box tracks Z coordinates.
# File lib/rgeo/cartesian/bounding_box.rb, line 153 def has_z @has_z end
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.
# File lib/rgeo/cartesian/bounding_box.rb, line 137 def infinitesimal? @min_x && @min_x == @max_x && @min_y == @max_y end
Returns the M span, 0 if this bounding box is empty, or nil if it has no M.
# File lib/rgeo/cartesian/bounding_box.rb, line 272 def m_span @has_m ? (@max_m ? @max_m - @min_m : 0) : nil end
Returns the maximum M, or nil if this bounding box is empty.
# File lib/rgeo/cartesian/bounding_box.rb, line 258 def max_m @max_m end
Returns a point representing the maximum extent in all dimensions, or nil if this bounding box is empty.
# File lib/rgeo/cartesian/bounding_box.rb, line 295 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_) else nil end end
Returns the maximum X, or nil if this bounding box is empty.
# File lib/rgeo/cartesian/bounding_box.rb, line 174 def max_x @max_x end
Returns the maximum Y, or nil if this bounding box is empty.
# File lib/rgeo/cartesian/bounding_box.rb, line 202 def max_y @max_y end
Returns the maximum Z, or nil if this bounding box is empty.
# File lib/rgeo/cartesian/bounding_box.rb, line 230 def max_z @max_z end
Returns the minimum M, or nil if this bounding box is empty.
# File lib/rgeo/cartesian/bounding_box.rb, line 251 def min_m @min_m end
Returns a point representing the minimum extent in all dimensions, or nil if this bounding box is empty.
# File lib/rgeo/cartesian/bounding_box.rb, line 280 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_) else nil end end
Returns the minimum X, or nil if this bounding box is empty.
# File lib/rgeo/cartesian/bounding_box.rb, line 167 def min_x @min_x end
Returns the minimum Y, or nil if this bounding box is empty.
# File lib/rgeo/cartesian/bounding_box.rb, line 195 def min_y @min_y end
Returns the minimum Z, or nil if this bounding box is empty.
# File lib/rgeo/cartesian/bounding_box.rb, line 223 def min_z @min_z end
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.
# File lib/rgeo/cartesian/bounding_box.rb, line 404 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
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).
# File lib/rgeo/cartesian/bounding_box.rb, line 332 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
Returns the X span, or 0 if this bounding box is empty.
# File lib/rgeo/cartesian/bounding_box.rb, line 188 def x_span @max_x ? @max_x - @min_x : 0 end
Returns the Y span, or 0 if this bounding box is empty.
# File lib/rgeo/cartesian/bounding_box.rb, line 216 def y_span @max_y ? @max_y - @min_y : 0 end
Returns the Z span, 0 if this bounding box is empty, or nil if it has no Z.
# File lib/rgeo/cartesian/bounding_box.rb, line 244 def z_span @has_z ? (@max_z ? @max_z - @min_z : 0) : nil end