Class: RGeo::Cartesian::BoundingBox

Inherits:
Object
  • Object
show all
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 Method Summary collapse

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.



74
75
76
77
78
79
# File 'lib/rgeo/cartesian/bounding_box.rb', line 74

def initialize(factory_, opts_={})
  @factory = factory_
  @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

Instance Method Details

#_add_geometry(geometry_) ⇒ Object

:nodoc:



285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
# File 'lib/rgeo/cartesian/bounding_box.rb', line 285

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
end

#_add_point(point_) ⇒ Object

:nodoc:



305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
# File 'lib/rgeo/cartesian/bounding_box.rb', line 305

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 encomass the given object, which may be a geometry or another bounding box. Returns self.



210
211
212
213
214
215
216
217
218
219
220
221
222
223
# File 'lib/rgeo/cartesian/bounding_box.rb', line 210

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(Factory.cast(geometry_, @factory))
    end
  end
  self
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.

Returns:

  • (Boolean)


266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
# File 'lib/rgeo/cartesian/bounding_box.rb', line 266

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

#empty? ⇒ Boolean

Returns true if this bounding box is still empty.

Returns:

  • (Boolean)


101
102
103
# File 'lib/rgeo/cartesian/bounding_box.rb', line 101

def empty?
  @min_x.nil?
end

#eql?(rhs_) ⇒ Boolean Also known as: ==

:nodoc:

Returns:

  • (Boolean)


82
83
84
85
86
87
88
# File 'lib/rgeo/cartesian/bounding_box.rb', line 82

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

#factory ⇒ Object

Returns the bounding box's factory.



94
95
96
# File 'lib/rgeo/cartesian/bounding_box.rb', line 94

def factory
  @factory
end

#has_m ⇒ Object

Returns true if this bounding box tracks M coordinates.



115
116
117
# File 'lib/rgeo/cartesian/bounding_box.rb', line 115

def has_m
  @has_m
end

#has_z ⇒ Object

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

Returns the maximum M, or nil if this bounding box is empty.



171
172
173
# File 'lib/rgeo/cartesian/bounding_box.rb', line 171

def max_m
  @max_m
end

#max_point ⇒ Object

Returns a point representing the maximum extent in all dimensions, or nil if this bounding box is empty.



194
195
196
197
198
199
200
201
202
203
# File 'lib/rgeo/cartesian/bounding_box.rb', line 194

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 ⇒ Object

Returns the maximum X, or nil if this bounding box is empty.



129
130
131
# File 'lib/rgeo/cartesian/bounding_box.rb', line 129

def max_x
  @max_x
end

#max_y ⇒ Object

Returns the maximum Y, or nil if this bounding box is empty.



143
144
145
# File 'lib/rgeo/cartesian/bounding_box.rb', line 143

def max_y
  @max_y
end

#max_z ⇒ Object

Returns the maximum Z, or nil if this bounding box is empty.



157
158
159
# File 'lib/rgeo/cartesian/bounding_box.rb', line 157

def max_z
  @max_z
end

#min_m ⇒ Object

Returns the minimum M, or nil if this bounding box is empty.



164
165
166
# File 'lib/rgeo/cartesian/bounding_box.rb', line 164

def min_m
  @min_m
end

#min_point ⇒ Object

Returns a point representing the minimum extent in all dimensions, or nil if this bounding box is empty.



179
180
181
182
183
184
185
186
187
188
# File 'lib/rgeo/cartesian/bounding_box.rb', line 179

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 ⇒ Object

Returns the minimum X, or nil if this bounding box is empty.



122
123
124
# File 'lib/rgeo/cartesian/bounding_box.rb', line 122

def min_x
  @min_x
end

#min_y ⇒ Object

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

Returns the minimum Z, or nil if this bounding box is empty.



150
151
152
# File 'lib/rgeo/cartesian/bounding_box.rb', line 150

def min_z
  @min_z
end

#to_geometry ⇒ Object

Converts this bounding box to an envelope polygon. Returns the empty collection if this bounding box is empty.



229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
# File 'lib/rgeo/cartesian/bounding_box.rb', line 229

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 @min_x == @max_x && @min_y == @max_y
      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 @min_x == @max_x || @min_y == @max_y
        @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