mirror of
https://github.com/boostorg/geometry.git
synced 2026-02-13 12:32:09 +00:00
318 lines
9.7 KiB
Plaintext
318 lines
9.7 KiB
Plaintext
[/============================================================================
|
|
Boost.Geometry Index (Spatial Indexes)
|
|
|
|
Copyright (c) 2008 Federico J. Fernandez.
|
|
Copyright (c) 2011 Adam Wulkiewicz.
|
|
|
|
Use, modification and distribution is subject to the Boost Software License,
|
|
Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
|
http://www.boost.org/LICENSE_1_0.txt)
|
|
=============================================================================/]
|
|
|
|
[section R-tree]
|
|
|
|
[section Introduction]
|
|
|
|
__rtree__ is a self-balancing search tree with nodes stored with their axis aligned
|
|
bounding boxes. Each node's box describes the space occupied by children nodes.
|
|
At the bottom of the structure, there are leaf-nodes which contains values
|
|
(geometric objects representations). Minimal and maximal numbers of values/children
|
|
which may be stored inside the node are user defined.
|
|
|
|
In order to use the __rtree__ one must include folowing file.
|
|
|
|
#include <boost/geometry/extensions/index/rtree/rtree.hpp>
|
|
|
|
[endsect]
|
|
|
|
[section R-tree creation]
|
|
|
|
[section Quick start]
|
|
|
|
In order to create a __rtree__ object storing values of type `std::pair<__box__, size_t>`
|
|
one may use the following code:
|
|
|
|
using namespace __cboost__::__cgeometry__;
|
|
typedef std::pair<__box__, size_t> Value;
|
|
index::rtree< Value, index::quadratic<32, 8> > rt;
|
|
|
|
[endsect]
|
|
|
|
[section R-tree template parameters]
|
|
|
|
__rtree__ has 4 parameters:
|
|
|
|
rtree<Value, Parameters, Translator, Allocator>
|
|
|
|
* `Value` - type of object which will be stored in the container.
|
|
* `Parameters` - compile-time parameters, e.g. inserting/splitting
|
|
algorithm with min and max nodes' elements numbers.
|
|
* `Translator` - type of object translating `Value` objects to
|
|
`Indexable` objects (`__point__` or `__box__`) which __rtree__ can handle.
|
|
* `Allocator` - the allocator.
|
|
|
|
[endsect]
|
|
|
|
[section Values, Indexables and default Translator]
|
|
|
|
__rtree__ may store `__value__`s of any type as long as there is passed
|
|
the `__translator__` which knows how to interpret those `__value__`s
|
|
and extract an object understandable by the __rtree__. Those objects are called
|
|
`__indexable__`s and they are simply of type adapted to `__point__`
|
|
or `__box__` concept. Default `__translator__` `index::translator::def<Value>`
|
|
is able to handle `__point__`, `__box__`, `std::pair<...>`, pointer, iterator
|
|
or smart pointer.
|
|
|
|
* `__indexable__ = __point__ | __box__`
|
|
* `BasicValue = Indexable | std::pair<__indexable__, T> | std::pair<T, __indexable__>`
|
|
* `__value__ = BasicValue | BasicValue* | Iterator<BasicValue> | SmartPtr<BasicValue>`
|
|
|
|
Examples of `__value__` types:
|
|
|
|
geometry::model::point<...>
|
|
geometry::model::point_xy<...>
|
|
geometry::model::box<...>
|
|
std::pair<geometry::model::box<...>, size_t>
|
|
|
|
[endsect]
|
|
|
|
[section Inserting and splitting algorithms]
|
|
|
|
`__value__`s may be inserted to the __rtree__ in many various ways. Final structure of nodes depends
|
|
on algorithms used in the process, especially nodes' splitting algorithm. Currently, three
|
|
well-known types of R-trees may be created.
|
|
|
|
Linear - classic __rtree__ using splitting algorithm of linear complexity
|
|
|
|
index::rtree< __value__, index::linear<32, 8> > rt;
|
|
|
|
Quadratic - classic __rtree__ using splitting algorithm of quadratic complexity
|
|
|
|
index::rtree< __value__, index::quadratic<32, 8> > rt;
|
|
|
|
R*-tree - splitting algorithm minimizing nodes' overlap with forced reinsertions
|
|
|
|
index::rtree< __value__, index::rstar<32, 8> > rt;
|
|
|
|
[endsect]
|
|
|
|
[endsect] [/ R-tree creation /]
|
|
|
|
[section Inserting and removing Values]
|
|
|
|
Create
|
|
|
|
using namespace boost::geometry;
|
|
typedef std::pair<Box, int> __value__;
|
|
index::rtree< __value__, index::quadratic<32, 8> > rt;
|
|
|
|
Insert and remove by method call
|
|
|
|
__value__ v = std::make_pair(__box__(...), 0);
|
|
rt.insert(v);
|
|
rt.remove(v);
|
|
|
|
or by function call
|
|
|
|
__value__ v = std::make_pair(__box__(...), 0);
|
|
index::insert(rt, v);
|
|
index::remove(rt, v);
|
|
|
|
[endsect]
|
|
|
|
[section Spatial queries]
|
|
|
|
[section Basic queries]
|
|
|
|
There are three ways to perform a spatial query. Following queries returns
|
|
`__value__`s intersecting some box_region.
|
|
|
|
Method call
|
|
|
|
std::vector<__value__> returned_values;
|
|
__box__ box_region(...);
|
|
rt.query(box_region, std::back_inserter(returned_values));
|
|
|
|
Function call
|
|
|
|
std::vector<__value__> returned_values;
|
|
__box__ box_region(...);
|
|
index::query(rt, box_region, std::back_inserter(returned_values));
|
|
|
|
Use of `operator |` (as with ranges)
|
|
|
|
__box__ box_region(...);
|
|
BOOST_FOREACH(__value__ & v, rt | index::query_filtered(box_region))
|
|
; // do something with v
|
|
[endsect]
|
|
|
|
[section Spatial predicates]
|
|
|
|
It is possible to define other relations between queried `__value__`s and region/regions
|
|
of interest. Names of predicates corresponds to names of __boost_geometry__ algorithms.
|
|
|
|
rt.query(box, std::back_inserter(result)); // default case - intersects
|
|
rt.query(index::intersects(box), std::back_inserter(result)); // same as default
|
|
rt.query(index::covered_by(box), std::back_inserter(result));
|
|
rt.query(index::disjont(box), std::back_inserter(result));
|
|
rt.query(index::overlaps(box), std::back_inserter(result));
|
|
rt.query(index::within(box), std::back_inserter(result));
|
|
|
|
All predicates may be negated, e.g.:
|
|
|
|
rt.query(index::not_intersects(box), std::back_inserter(result));
|
|
// or
|
|
rt.query(!index::intersects(box), std::back_inserter(result));
|
|
// the same as
|
|
rt.query(index::disjoint(box), std::back_inserter(result));
|
|
|
|
It's possible to use some number of predicates by passing `std::pair<Pred1, Pred2>`
|
|
|
|
rt.query(
|
|
std::make_pair(index::intersects(box1), !index::within(box2))
|
|
, std::back_inserter(result));
|
|
|
|
or `boost::tuple<Pred1, Pred2, Pred3, ...>`
|
|
|
|
rt.query(
|
|
boost::make_tuple(
|
|
index::intersects(box1), !index::within(box2), index::overlaps(box3))
|
|
, std::back_inserter(result));
|
|
|
|
There is also a unique predicate `index::value(...)` taking user-defined function/functor
|
|
which checks if `__value__` should be returned by the query.
|
|
|
|
bool fun(__value const& v)
|
|
{
|
|
return v.is_red();
|
|
}
|
|
|
|
// ...
|
|
|
|
rt.query(
|
|
boost::make_pair(index::intersects(box), index::value(fun))
|
|
, std::back_inserter(result));
|
|
|
|
[endsect]
|
|
|
|
[endsect] [/ Spatial queries /]
|
|
|
|
[section Nearest neighbors queries]
|
|
|
|
[section k nearest neighbors]
|
|
|
|
There are three ways of performing knn queries. Following queries returns
|
|
k `__value__`s closest to some point in space. For `__box__`es
|
|
`__indexable__`s closest point of a `__box__` is taken into account by default.
|
|
|
|
Method call
|
|
|
|
std::vector<__value__> returned_values;
|
|
__point__ pt(...);
|
|
rt.nearest(pt, k, std::back_inserter(returned_values));
|
|
|
|
Function call
|
|
|
|
std::vector<__value__> returned_values;
|
|
__point__ pt(...);
|
|
index::nearest(rt, pt, k, std::back_inserter(returned_values));
|
|
|
|
Use of `operator |`
|
|
|
|
__point__ pt(...);
|
|
BOOST_FOREACH(__value__ & v, rt | index::nearest_filtered(pt, k))
|
|
; // do something with v
|
|
|
|
[endsect]
|
|
|
|
[section One nearest neighbor]
|
|
|
|
Another type of nearest neighbor query is searching for the one closest `__value__`.
|
|
If it is found, 1 is returned by the method or function. This kind of query
|
|
has only two forms.
|
|
|
|
Method call
|
|
|
|
__value__ returned_value;
|
|
__point__ pt(...);
|
|
size_t n = rt.nearest(pt, returned_value);
|
|
|
|
Function call
|
|
|
|
__value__ Value returned_value;
|
|
__point__ pt(...);
|
|
size_t n = index::nearest(rt, pt, returned_value);
|
|
|
|
[endsect]
|
|
|
|
[section Distances predicates]
|
|
|
|
It is possible to define if calculated distance between query point and `__value__` should be
|
|
greater, lesser or between some other distances. Those are called `DistancesPredicate`s and
|
|
may be defined as follows.
|
|
|
|
std::vector<__Value__> returned_values;
|
|
__point__ pt(...);
|
|
|
|
/* default - without bounds */
|
|
index::nearest(rt, pt, k, std::back_inserter(returned_values));
|
|
|
|
/* same as default */
|
|
index::nearest(rt, index::unbounded(pt), k, std::back_inserter(returned_values));
|
|
|
|
/* distance must be greater than or equal to 10 */
|
|
index::nearest(rt, index::min_bounded(pt, 10), k, std::back_inserter(returned_values));
|
|
|
|
/* distance must be lesser than or equal to 500 */
|
|
index::nearest(rt, index::max_bounded(pt, 500), k, std::back_inserter(returned_values));
|
|
|
|
/* distance must be between 10 and 500 */
|
|
index::nearest(rt, index::bounded(pt, 10, 500), k, std::back_inserter(returned_values));
|
|
|
|
Furthermore, it's possible to define if the closest, furthest or centroidal point of the
|
|
non-point `__indexable__` should be taken into account in the routine calculating distance.
|
|
|
|
std::vector<__value__> returned_values;
|
|
__point__ pt(...);
|
|
|
|
/* default - distance between Indexable's closest point and a query point
|
|
must be greater than 10 */
|
|
index::nearest(rt, index::min_bounded(pt, 10), k, std::back_inserter(returned_values));
|
|
|
|
/* same as default - distance between Indexable's closest point and a query point
|
|
must be greater than 10 */
|
|
index::nearest(rt, index::min_bounded(pt, index::near(10)), k, std::back_inserter(returned_values));
|
|
|
|
/* distance between Indexable's furthest point and a query point
|
|
must be greater than 10 */
|
|
index::nearest(rt, index::min_bounded(pt, index::far(10)), k, std::back_inserter(returned_values));
|
|
|
|
/* distance between Indexable's centroid and a query point
|
|
must be greater than 10 */
|
|
index::nearest(rt, index::min_bounded(pt, index::centroid(10)), k, std::back_inserter(returned_values));
|
|
|
|
[endsect]
|
|
|
|
[section Using spatial predicates]
|
|
|
|
It is possible to use spatial predicates described before in nearest neighbors queries.
|
|
|
|
__value__ returned_value;
|
|
std::vector<__value__> returned_values;
|
|
|
|
__point__ pt(...);
|
|
__box__ b(...);
|
|
|
|
size_t n1 = rt.nearest(index::bounded(pt, index::far(1), 10), index::intersects(b), returned_value);
|
|
|
|
size_t n2 = index::nearest(rt, pt, k, index::within(b), std::back_inserter(returned_values));
|
|
|
|
BOOST_FOREACH(Value & v, rt | index::nearest_filtered(pt, k, index::covered_by(b)))
|
|
; // do something with v
|
|
|
|
[endsect]
|
|
|
|
[endsect] [/ Nearest neighbors queries /]
|
|
|
|
[endsect] [/ R-tree /]
|