class RGeo::Cartesian::BoundingBox

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.

Public Class Methods

create_from_geometry(geom_, opts_={}) click to toggle source

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_from_points(point1_, point2_, opts_={}) click to toggle source

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
new(factory_, opts_={}) click to toggle source

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

Public Instance Methods

add(geometry_) click to toggle source

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
center_m() click to toggle source

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
center_x() click to toggle source

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
center_y() click to toggle source

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
center_z() click to toggle source

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
contains?(rhs_, opts_={}) click to toggle source

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
degenerate?() click to toggle source

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
empty?() click to toggle source

Returns true if this bounding box is still empty.

# File lib/rgeo/cartesian/bounding_box.rb, line 127
def empty?
  @min_x.nil?
end
factory() click to toggle source

Returns the bounding box’s factory.

# File lib/rgeo/cartesian/bounding_box.rb, line 120
def factory
  @factory
end
has_m() click to toggle source

Returns true if this bounding box tracks M coordinates.

# File lib/rgeo/cartesian/bounding_box.rb, line 160
def has_m
  @has_m
end
has_z() click to toggle source

Returns true if this bounding box tracks Z coordinates.

# File lib/rgeo/cartesian/bounding_box.rb, line 153
def has_z
  @has_z
end
infinitesimal?() click to toggle source

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
m_span() click to toggle source

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
max_m() click to toggle source

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
max_point() click to toggle source

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
max_x() click to toggle source

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
max_y() click to toggle source

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
max_z() click to toggle source

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
min_m() click to toggle source

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
min_point() click to toggle source

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
min_x() click to toggle source

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
min_y() click to toggle source

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
min_z() click to toggle source

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
subdivide(opts_={}) click to toggle source

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
to_geometry() click to toggle source

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
x_span() click to toggle source

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
y_span() click to toggle source

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
z_span() click to toggle source

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