]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | [/============================================================================ |
2 | Boost.Geometry Index | |
3 | ||
4 | Copyright (c) 2011-2013 Adam Wulkiewicz. | |
5 | ||
6 | Use, modification and distribution is subject to the Boost Software License, | |
7 | Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at | |
8 | http://www.boost.org/LICENSE_1_0.txt) | |
9 | =============================================================================/] | |
10 | ||
11 | [section Queries] | |
12 | ||
13 | Queries returns `__value__`s which meets some predicates. Currently supported are three types of predicates: | |
14 | ||
15 | * spatial predicates - spatial conditions that must be met by stored Value and some Geometry, | |
16 | * distance predicates - distance conditions that must be met by stored Value and some Geometry, | |
17 | * user-defined unary predicate - function, function object or lambda expression checking user-defined condition. | |
18 | ||
19 | For example queries may be used to retrieve Values: | |
20 | ||
21 | * intersecting some area but not within other area, | |
22 | * are nearest to some point, | |
23 | * overlapping a box and has user-defined property. | |
24 | ||
25 | [h4 Performing a query] | |
26 | ||
27 | There are various ways to perform a query. They are presented below. | |
28 | All of them returns `__value__`s intersecting some region defined as a `__box__`. | |
29 | ||
30 | Member function call | |
31 | ||
32 | std::vector<__value__> returned_values; | |
33 | __box__ box_region(...); | |
34 | rt.query(bgi::intersects(box_region), std::back_inserter(returned_values)); | |
35 | ||
36 | Free function call | |
37 | ||
38 | std::vector<__value__> returned_values; | |
39 | __box__ box_region(...); | |
40 | bgi::query(rt, bgi::intersects(box_region), std::back_inserter(returned_values)); | |
41 | ||
42 | Range generated by `operator|` | |
43 | ||
44 | __box__ box_region(...); | |
45 | BOOST_FOREACH(__value__ & v, rt | bgi::adaptors::queried(bgi::intersects(box_region))) | |
46 | ; // do something with v | |
47 | ||
48 | Query iterators returned by member functions | |
49 | ||
50 | std::vector<__value__> returned_values; | |
51 | __box__ box_region(...); | |
52 | std::copy(rt.qbegin(bgi::intersects(box_region)), rt.qend(), std::back_inserter(returned_values)); | |
53 | ||
54 | Query iterators returned by free functions | |
55 | ||
56 | std::vector<__value__> returned_values; | |
57 | __box__ box_region(...); | |
58 | std::copy(bgi::qbegin(rt, bgi::intersects(box_region)), bgi::qend(rt), std::back_inserter(returned_values)); | |
59 | ||
60 | [h4 Spatial predicates] | |
61 | ||
62 | Queries using spatial predicates returns `__value__`s which are related somehow to some Geometry - box, polygon, etc. | |
63 | Names of spatial predicates correspond to names of __boost_geometry__ algorithms (boolean operations). | |
64 | Examples of some basic queries may be found in the tables below. The query region and result `Value`s are orange. | |
65 | ||
66 | [table | |
67 | [[intersects(Box)] [covered_by(Box)] [disjoint(Box)] [overlaps(Box)] [within(Box)]] | |
68 | [[[$img/index/rtree/intersects.png]] [[$img/index/rtree/within.png]] [[$img/index/rtree/disjoint.png]] [[$img/index/rtree/overlaps.png]] [[$img/index/rtree/within.png]]] | |
69 | ] | |
70 | ||
71 | [table | |
72 | [[intersects(Ring)] [intersects(Polygon)] [intersects(MultiPolygon)] [intersects(Segment)] [intersects(Linestring)]] | |
73 | [[[$img/index/rtree/intersects_ring.png]] [[$img/index/rtree/intersects_poly.png]] [[$img/index/rtree/intersects_mpoly.png]] [[$img/index/rtree/intersects_segment.png]] [[$img/index/rtree/intersects_linestring.png]]] | |
74 | ] | |
75 | ||
76 | [table | |
77 | [[intersects(Box)] [disjoint(Box)] [intersects(Box)] [disjoint(Box)]] | |
78 | [[[$img/index/rtree/rtree_pt_intersects_box.png]] [[$img/index/rtree/rtree_pt_disjoint_box.png]] [[$img/index/rtree/rtree_seg_intersects_box.png]] [[$img/index/rtree/rtree_seg_disjoint_box.png]]] | |
79 | ] | |
80 | ||
81 | Spatial predicates are generated by functions defined in `boost::geometry::index` namespace. | |
82 | ||
83 | rt.query(index::contains(box), std::back_inserter(result)); | |
84 | rt.query(index::covered_by(box), std::back_inserter(result)); | |
85 | rt.query(index::covers(box), std::back_inserter(result)); | |
86 | rt.query(index::disjont(box), std::back_inserter(result)); | |
87 | rt.query(index::intersects(box), std::back_inserter(result)); | |
88 | rt.query(index::overlaps(box), std::back_inserter(result)); | |
89 | rt.query(index::within(box), std::back_inserter(result)); | |
90 | ||
91 | All spatial predicates may be negated, e.g.: | |
92 | ||
93 | rt.query(!index::intersects(box), std::back_inserter(result)); | |
94 | // the same as | |
95 | rt.query(index::disjoint(box), std::back_inserter(result)); | |
96 | ||
97 | [h4 Nearest neighbours queries] | |
98 | ||
99 | Nearest neighbours queries returns `__value__`s which are closest to some Geometry. | |
100 | The examples of k-NN queries are presented below. 5 `__value__`s nearest to the Geometry are orange. | |
101 | ||
102 | [table | |
103 | [[nearest(Point, k)] [nearest(Box, k)] [nearest(Point, k)] [nearest(Box, k)]] | |
104 | [[[$img/index/rtree/knn_pt_box.png]] [[$img/index/rtree/knn_box_box.png]] [[$img/index/rtree/rtree_pt_knn_pt.png]] [[$img/index/rtree/rtree_pt_knn_box.png]]] | |
105 | ] | |
106 | [table | |
107 | [[nearest(Segment, k)] | |
108 | [nearest(Point, k)] [nearest(Box, k)] [nearest(Segment, k)] | |
109 | [nearest(Segment, k)]] | |
110 | [[[$img/index/rtree/knn_seg_box.png]] | |
111 | [[$img/index/rtree/rtree_seg_knn_pt.png]] [[$img/index/rtree/rtree_seg_knn_box.png]] [[$img/index/rtree/rtree_seg_knn_seg.png]] | |
112 | [[$img/index/rtree/rtree_pt_knn_seg.png]]] | |
113 | ] | |
114 | ||
115 | To perform the knn query one must pass the nearest predicate generated by the | |
116 | `nearest()` function defined in `boost::geometry::index` namespace. | |
117 | For non-point `__indexable__`s the shortest distance is calculated using `bg::comparable_distance()` function. | |
118 | The following query returns `k` `__value__`s closest to some Point in space. | |
119 | ||
120 | std::vector<__value__> returned_values; | |
121 | __point__ pt(/*...*/); | |
122 | rt.query(bgi::nearest(pt, k), std::back_inserter(returned_values)); | |
123 | ||
124 | The same way different query Geometries can be used: | |
125 | ||
126 | __box__ box(/*...*/); | |
127 | rt.query(bgi::nearest(box, k), std::back_inserter(returned_values)); | |
128 | ||
129 | Segment seg(/*...*/); | |
130 | rt.query(bgi::nearest(seg, k), std::back_inserter(returned_values)); | |
131 | ||
132 | [h4 User-defined unary predicate] | |
133 | ||
134 | The user may pass a `UnaryPredicate` - function, function object or lambda expression taking const reference to Value and returning bool. | |
135 | This object may be passed to the query in order to check if `__value__` should be returned by the query. To do it one | |
136 | may use `index::satisfies()` function like on the example below: | |
137 | ||
138 | bool is_red(__value__ const& v) | |
139 | { | |
140 | return v.is_red(); | |
141 | } | |
142 | ||
143 | struct is_red_o | |
144 | { | |
145 | template <typename Value> | |
146 | bool operator()(__value__ const& v) | |
147 | { | |
148 | return v.is_red(); | |
149 | } | |
150 | } | |
151 | ||
152 | // ... | |
153 | ||
154 | rt.query(index::intersects(box) && index::satisfies(is_red), | |
155 | std::back_inserter(result)); | |
156 | ||
157 | rt.query(index::intersects(box) && index::satisfies(is_red_o()), | |
158 | std::back_inserter(result)); | |
159 | ||
160 | #ifndef BOOST_NO_CXX11_LAMBDAS | |
161 | rt.query(index::intersects(box) && index::satisfies([](__value__ const& v) { return v.is_red(); }), | |
162 | std::back_inserter(result)); | |
163 | #endif | |
164 | ||
165 | `satisfies()` may be negated, e.g.: | |
166 | ||
167 | bool is_red(__value__ const& v) { return v.is_red(); } | |
168 | bool is_not_red(__value__ const& v) { return !v.is_red(); } | |
169 | ||
170 | // ... | |
171 | ||
172 | rt.query(index::intersects(box) && index::satisfies(is_red), | |
173 | std::back_inserter(result)); | |
174 | // the same as | |
175 | rt.query(index::intersects(box) && !index::satisfies(is_not_red), | |
176 | std::back_inserter(result)); | |
177 | ||
178 | [h4 Passing a set of predicates] | |
179 | ||
180 | It's possible to use some number of predicates in one query by connecting them with `operator&&` e.g. `Pred1 && Pred2 && Pred3 && ...`. | |
181 | ||
182 | These predicates are connected by logical AND. Passing all predicates together not only makes possible | |
183 | to construct advanced queries but is also faster than separate calls because the tree is traversed only once. | |
184 | Traversing is continued and `Value`s are returned only if all predicates are met. Predicates are checked | |
185 | left-to-right so placing most restrictive predicates first should accelerate the search. | |
186 | ||
187 | rt.query(index::intersects(box1) && !index::within(box2), | |
188 | std::back_inserter(result)); | |
189 | ||
190 | rt.query(index::intersects(box1) && !index::within(box2) && index::overlaps(box3), | |
191 | std::back_inserter(result)); | |
192 | ||
193 | Of course it's possible to connect different types of predicates together. | |
194 | ||
195 | index::query(rt, index::nearest(pt, k) && index::within(b), std::back_inserter(returned_values)); | |
196 | ||
197 | BOOST_FOREACH(Value & v, rt | index::adaptors::queried(index::nearest(pt, k) && index::covered_by(b))) | |
198 | ; // do something with v | |
199 | ||
200 | [h4 Iterative queries] | |
201 | ||
202 | The query performed using query iterators may be paused and resumed if needed, e.g. when the query takes too long, | |
203 | or may be stopped at some point, when all interesting values were gathered. The query iterator is returned by | |
204 | `qbegin()` member function which requires passing predicates, like `query()` member function. | |
205 | ||
206 | for ( Rtree::const_query_iterator it = tree.qbegin(bgi::nearest(pt, 10000)) ; | |
207 | it != tree.qend() ; ++it ) | |
208 | { | |
209 | // do something with value | |
210 | if ( has_enough_nearest_values() ) | |
211 | break; | |
212 | } | |
213 | ||
214 | [note In the case of iterative k-NN queries it's guaranteed to iterate over the closest `__value__`s first. ] | |
215 | ||
216 | [warning The modification of the `rtree`, e.g. insertion or removal of `__value__`s may invalidate the iterators. ] | |
217 | ||
218 | [h4 Inserting query results into the other R-tree] | |
219 | ||
220 | There are several ways of inserting Values returned by a query to the other R-tree container. | |
221 | The most basic way is creating a temporary container for Values and insert them later. | |
222 | ||
223 | namespace bgi = boost::geometry::index; | |
224 | typedef std::pair<Box, int> __value__; | |
225 | typedef bgi::rtree< __value__, bgi::linear<32, 8> > RTree; | |
226 | ||
227 | RTree rt1; | |
228 | /* some inserting into the tree */ | |
229 | ||
230 | std::vector<Value> result; | |
231 | rt1.query(bgi::intersects(Box(/*...*/)), std::back_inserter(result)); | |
232 | RTree rt2(result.begin(), result.end()); | |
233 | ||
234 | However there are better ways. One of these methods is mentioned in the "Creation and modification" section. | |
235 | The insert iterator may be passed directly into the query. | |
236 | ||
237 | RTree rt3; | |
238 | rt1.query(bgi::intersects(Box(/*...*/))), bgi::inserter(rt3)); | |
239 | ||
240 | If you're a user of Boost.Range you'll appreciate the third option. You may pass the result Range directly into the | |
241 | constructor or `insert()` member function. | |
242 | ||
243 | RTree rt4(rt1 | bgi::adaptors::queried(bgi::intersects(Box(/*...*/))))); | |
244 | ||
245 | [endsect] [/ Queries /] |