Class: RTree
Overview
A Ruby wrapper around librtree implementing the R-tree spatial index of Guttman-Green.
Use
require 'rtree'
to make the RTree class available.
Given a set or rectangles (or higher dimensional cuboids) and their associated ids, one can build an RTree using the RTree.csv_read class method or repeated calls to the #add_rect instance method. The former is more performant since it avoids routing the rectangles through the Ruby-C interface.
Once the RTree instance is created one can make spatial queries against it with the #search method; one passes a rectangle to the method and it returns the ids of all of the input rectangles which intersect it (or yields them one at a time to a block, if given).
It may be convenient to serialise the RTree for faster loading, the library implements a custom binary format, BSRT (binary serialised R-tree) which can be written by #bsrt_write and read with RTree.bsrt_read. One can also serialise to JSON, but this results in a much larger file (a factor of ten) and so correspondingly slow to read/write. Useful, nevertheless, for debugging and loading into a native Ruby hash format (see #to_h).
All rectangles used in the library are simply arrays of floats, the lower value for each dimension, followed by the upper value for each dimension. Thus
[0, 0, 1, 2]
is the rectangle with 0 ≤ x ≤ 1 and 0 ≤ y ≤ 2. Upper and lower values may coincide (to create a line segment in 2-space, for example) but a lower value larger than the upper value will cause an error.
It is anticipated that the ids passed to the library will be used as an index for application specific data to which this rectangle relates (its location in an array, or a DB id) but this is entirely at the discretion of the caller, the library makes no use of the value, treating it as payload. In particular, the value may be non-unique and may be zero. One should note that the id type used internally by the library is determined at compile-time (with the RTREE_ID_TYPE variable) and by default this is a 64-bit unsigned integer.
Class Method Summary collapse
-
.bsrt_read(io) ⇒ RTree
Create a new RTree instance from BSRT (binary serialised R-tree) stream.
-
.bugreport ⇒ String
Email address for librtree bug reports.
-
.csv_read(io, dim, split: :quadratic, node_page: 0) ⇒ RTree
Build a new RTree instance from CSV stream.
-
.from_bsrt(bsrt) ⇒ RTree
Create a new RTree instance from BSRT (binary serialised R-tree) string.
-
.from_csv(csv, dim, **kwarg) ⇒ RTree
Build a new RTree instance from CSV string.
-
.from_json(json) ⇒ RTree
Create a new RTree instance from JSON string.
-
.json_read(io) ⇒ RTree
Create a new RTree instance from JSON stream.
-
.url ⇒ String
Librtree homepage.
-
.version ⇒ Array<Integer>
Version of librtree.
Instance Method Summary collapse
-
#add_rect(id, coords) ⇒ self
Add a rectangle to the RTree.
-
#branch_size ⇒ Integer
The size in bytes of a branch.
-
#branching_factor ⇒ Integer
The number of branches from each node.
-
#bsrt_write(io) ⇒ self
Serialise to BSRT (binary serialised R-tree) stream.
-
#clone ⇒ RTree
Create a deep copy.
-
#dim ⇒ Integer
The dimension of the R-tree.
-
#empty? ⇒ Boolean
Whether the RTree has any rectangles or not.
-
#eq?(other) ⇒ Boolean
(also: #==)
Equality of RTrees.
-
#height ⇒ Integer
The height to the tree in the usual mathematical sense.
-
#initialize(dim, split: :quadratic, node_page: 0) ⇒ RTree
constructor
Initialize a new (empty) RTree.
-
#json_write(io) ⇒ self
Serialise to JSON stream.
-
#node_size ⇒ Integer
The size in bytes of a node.
-
#page_size ⇒ Integer
The bytes in a page of memory.
-
#rect_size ⇒ Integer
The size in bytes of a rectangle.
-
#search(coords) ⇒ Array<Integer>
Search the RTree.
-
#size ⇒ Integer
The total bytes allocated for the instance.
-
#to_bsrt ⇒ String
Serialise to BSRT string.
-
#to_h ⇒ Hash
The RTree structure in hash form.
-
#to_json ⇒ String
Serialise to JSON string.
-
#unit_sphere_volume ⇒ Float
The volume of the unit sphere in the R-tree’s dimension.
-
#update! {|id, coords| ... } ⇒ self
Update the RTree.
Constructor Details
#initialize(dim, split: :quadratic, node_page: 0) ⇒ RTree
Initialize a new (empty) RTree
195 196 197 198 199 |
# File 'lib/rtree.rb', line 195 def initialize(dim, split: :quadratic, node_page: 0) @split = split @node_page = node_page super(dim, flags) end |
Class Method Details
.bsrt_read(io) ⇒ RTree
Create a new RTree instance from BSRT (binary serialised R-tree) stream
83 84 85 |
# File 'lib/rtree.rb', line 83 def bsrt_read(io) super end |
.bugreport ⇒ String
Returns email address for librtree bug reports.
129 130 131 |
# File 'lib/rtree.rb', line 129 def bugreport super end |
.csv_read(io, dim, split: :quadratic, node_page: 0) ⇒ RTree
The CSV file (without header) should have the id in the first column, then twice as many floats as the dimension. Extra columns may be present and will be ignored (this useful feature is the reason that the dimension is a required argument).
Build a new RTree instance from CSV stream
107 108 109 110 |
# File 'lib/rtree.rb', line 107 def csv_read(io, dim, split: :quadratic, node_page: 0) flags = split_flag(split) | node_page_flag(node_page) super(io, dim, flags) end |
.from_bsrt(bsrt) ⇒ RTree
Create a new RTree instance from BSRT (binary serialised R-tree) string
92 93 94 |
# File 'lib/rtree.rb', line 92 def from_bsrt(bsrt) deserialise(bsrt, Encoding::BINARY) { |io| bsrt_read(io) } end |
.from_csv(csv, dim, **kwarg) ⇒ RTree
Build a new RTree instance from CSV string
117 118 119 120 121 |
# File 'lib/rtree.rb', line 117 def from_csv(csv, dim, **kwarg) deserialise(csv, Encoding::UTF_8) do |io| csv_read(io, dim, **kwarg) end end |
.from_json(json) ⇒ RTree
Create a new RTree instance from JSON string
72 73 74 |
# File 'lib/rtree.rb', line 72 def from_json(json) deserialise(json, Encoding::UTF_8) { |io| json_read(io) } end |
.json_read(io) ⇒ RTree
Create a new RTree instance from JSON stream
64 65 66 |
# File 'lib/rtree.rb', line 64 def json_read(io) super end |
.url ⇒ String
Returns librtree homepage.
134 135 136 |
# File 'lib/rtree.rb', line 134 def url super end |
.version ⇒ Array<Integer>
Returns version of librtree.
124 125 126 |
# File 'lib/rtree.rb', line 124 def version @version ||= super.split('.').map(&:to_i) end |
Instance Method Details
#add_rect(id, coords) ⇒ self
Add a rectangle to the RTree
219 220 221 |
# File 'lib/rtree.rb', line 219 def add_rect(id, coords) super end |
#branch_size ⇒ Integer
Returns the size in bytes of a branch.
351 352 353 |
# File 'lib/rtree.rb', line 351 def branch_size super end |
#branching_factor ⇒ Integer
Returns the number of branches from each node.
356 357 358 |
# File 'lib/rtree.rb', line 356 def branching_factor super end |
#bsrt_write(io) ⇒ self
Serialise to BSRT (binary serialised R-tree) stream
285 286 287 |
# File 'lib/rtree.rb', line 285 def bsrt_write(io) super end |
#dim ⇒ Integer
Returns the dimension of the R-tree.
321 322 323 |
# File 'lib/rtree.rb', line 321 def dim super end |
#empty? ⇒ Boolean
Whether the RTree has any rectangles or not
265 266 267 |
# File 'lib/rtree.rb', line 265 def empty? height == 0 end |
#eq?(other) ⇒ Boolean Also known as: ==
Equality of RTrees. This is a rather strict equality, not only must the tree have the same rectangles, they must be in the same order. Certainly #clone will produce an instance which is equal in this sense.
314 315 316 |
# File 'lib/rtree.rb', line 314 def eq?(other) super end |
#height ⇒ Integer
The height to the tree in the usual mathematical sense
259 260 261 |
# File 'lib/rtree.rb', line 259 def height super end |
#json_write(io) ⇒ self
Serialise to JSON stream
275 276 277 |
# File 'lib/rtree.rb', line 275 def json_write(io) super end |
#node_size ⇒ Integer
Returns the size in bytes of a node.
341 342 343 |
# File 'lib/rtree.rb', line 341 def node_size super end |
#page_size ⇒ Integer
Returns the bytes in a page of memory.
336 337 338 |
# File 'lib/rtree.rb', line 336 def page_size super end |
#rect_size ⇒ Integer
Returns the size in bytes of a rectangle.
346 347 348 |
# File 'lib/rtree.rb', line 346 def rect_size super end |
#search(coords) ⇒ Array<Integer>
Search the RTree
228 229 230 231 232 233 234 235 236 |
# File 'lib/rtree.rb', line 228 def search(coords) if block_given? then super else ids = [] super(coords) { |id| ids << id } ids end end |
#size ⇒ Integer
This method traverses the entire tree summing the contributions for each node (rather than maintaining a running count). Performance-minded users may wish to cache this value (invalidating the cache when calling #add_rect of course).
Returns the total bytes allocated for the instance.
331 332 333 |
# File 'lib/rtree.rb', line 331 def size super end |
#to_bsrt ⇒ String
Serialise to BSRT string
299 300 301 |
# File 'lib/rtree.rb', line 299 def to_bsrt serialise(Encoding::BINARY) { |io| bsrt_write(io) } end |
#to_h ⇒ Hash
The RTree structure in hash form
305 306 307 |
# File 'lib/rtree.rb', line 305 def to_h JSON.parse(to_json, symbolize_names: true) end |
#to_json ⇒ String
Serialise to JSON string
292 293 294 |
# File 'lib/rtree.rb', line 292 def to_json serialise(Encoding::UTF_8) { |io| json_write(io) } end |
#unit_sphere_volume ⇒ Float
Returns the volume of the unit sphere in the R-tree’s dimension.
362 363 364 |
# File 'lib/rtree.rb', line 362 def unit_sphere_volume super end |
#update! {|id, coords| ... } ⇒ self
In the C library, the implementation (via a C callback function) is much faster than rebuilding the R-tree; in this Ruby interface the callback must convert C floats to Ruby, yield them to the block and then convert the returned Ruby Floats to C; so we would expect that it loses much of its competitive advantage when compared to an R-tree rebuild.
Update the RTree. Modifies the rectangles in-place without changing the tree structure. Provided that the changes are small, the search efficiency should be close to that of freshly built RTree.
253 254 255 |
# File 'lib/rtree.rb', line 253 def update! super end |