1 // Boost.Geometry Index
2 // OpenGL visualization
3
4 // Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland.
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 #include <GL/glut.h>
11
12 #include <boost/foreach.hpp>
13
14 #include <boost/geometry.hpp>
15 #include <boost/geometry/index/rtree.hpp>
16
17 #include <boost/geometry/geometries/linestring.hpp>
18 #include <boost/geometry/geometries/segment.hpp>
19 #include <boost/geometry/geometries/ring.hpp>
20 #include <boost/geometry/geometries/polygon.hpp>
21 #include <boost/geometry/geometries/multi_polygon.hpp>
22
23 #include <boost/geometry/index/detail/rtree/utilities/gl_draw.hpp>
24 #include <boost/geometry/index/detail/rtree/utilities/print.hpp>
25 #include <boost/geometry/index/detail/rtree/utilities/are_boxes_ok.hpp>
26 #include <boost/geometry/index/detail/rtree/utilities/are_levels_ok.hpp>
27 #include <boost/geometry/index/detail/rtree/utilities/statistics.hpp>
28
29 #include <boost/variant.hpp>
30
31 #define ENABLE_POINTS_AND_SEGMENTS
32
33 namespace bg = boost::geometry;
34 namespace bgi = bg::index;
35
36 // used types
37
38 typedef bg::model::point<float, 2, boost::geometry::cs::cartesian> P;
39 typedef bg::model::box<P> B;
40 typedef bg::model::linestring<P> LS;
41 typedef bg::model::segment<P> S;
42 typedef bg::model::ring<P> R;
43 typedef bg::model::polygon<P> Poly;
44 typedef bg::model::multi_polygon<Poly> MPoly;
45
46 // containers variant
47
48 template <typename V>
49 struct containers
50 {
operator =containers51 containers & operator=(containers const& c)
52 {
53 tree = c.tree;
54 values = c.values;
55 result = c.result;
56 return *this;
57 }
58
59 bgi::rtree< V, bgi::rstar<4, 2> > tree;
60 std::vector<V> values;
61 std::vector<V> result;
62 };
63
64 boost::variant<
65 containers<B>
66 #ifdef ENABLE_POINTS_AND_SEGMENTS
67 , containers<P>
68 , containers<S>
69 #endif
70 > cont;
71
72 // visitors
73
74 template <typename Pred>
75 struct query_v : boost::static_visitor<size_t>
76 {
77 Pred m_pred;
query_vquery_v78 query_v(Pred const& pred) : m_pred(pred) {}
79
80 template <typename C>
operator ()query_v81 size_t operator()(C & c) const
82 {
83 c.result.clear();
84 return c.tree.query(m_pred, std::back_inserter(c.result));
85 }
86 };
87 template <typename Cont, typename Pred>
query(Cont & cont,Pred const & pred)88 inline size_t query(Cont & cont, Pred const& pred)
89 {
90 return boost::apply_visitor(query_v<Pred>(pred), cont);
91 }
92
93 struct print_result_v : boost::static_visitor<>
94 {
95 template <typename C>
operator ()print_result_v96 void operator()(C & c) const
97 {
98 for ( size_t i = 0 ; i < c.result.size() ; ++i )
99 {
100 bgi::detail::utilities::print_indexable(std::cout, c.result[i]);
101 std::cout << '\n';
102 }
103 }
104 };
105 template <typename Cont>
print_result(Cont const & cont)106 inline void print_result(Cont const& cont)
107 {
108 boost::apply_visitor(print_result_v(), cont);
109 }
110
111 struct bounds_v : boost::static_visitor<B>
112 {
113 template <typename C>
operator ()bounds_v114 B operator()(C & c) const
115 {
116 return c.tree.bounds();
117 }
118 };
119 template <typename Cont>
bounds(Cont const & cont)120 inline B bounds(Cont const& cont)
121 {
122 return boost::apply_visitor(bounds_v(), cont);
123 }
124
125 struct depth_v : boost::static_visitor<size_t>
126 {
127 template <typename C>
operator ()depth_v128 size_t operator()(C & c) const
129 {
130 return get(c.tree);
131 }
132 template <typename RTree>
getdepth_v133 static size_t get(RTree const& t)
134 {
135 return bgi::detail::rtree::utilities::view<RTree>(t).depth();
136 }
137 };
138 template <typename Cont>
depth(Cont const & cont)139 inline size_t depth(Cont const& cont)
140 {
141 return boost::apply_visitor(depth_v(), cont);
142 }
143
144 struct draw_tree_v : boost::static_visitor<>
145 {
146 template <typename C>
operator ()draw_tree_v147 void operator()(C & c) const
148 {
149 bgi::detail::rtree::utilities::gl_draw(c.tree);
150 }
151 };
152 template <typename Cont>
draw_tree(Cont const & cont)153 inline void draw_tree(Cont const& cont)
154 {
155 return boost::apply_visitor(draw_tree_v(), cont);
156 }
157
158 struct draw_result_v : boost::static_visitor<>
159 {
160 template <typename C>
operator ()draw_result_v161 void operator()(C & c) const
162 {
163 for ( size_t i = 0 ; i < c.result.size() ; ++i )
164 {
165 bgi::detail::utilities::gl_draw_indexable(c.result[i], depth_v::get(c.tree));
166 }
167 }
168 };
169 template <typename Cont>
draw_result(Cont const & cont)170 inline void draw_result(Cont const& cont)
171 {
172 return boost::apply_visitor(draw_result_v(), cont);
173 }
174
175 struct print_tree_v : boost::static_visitor<>
176 {
177 template <typename C>
operator ()print_tree_v178 void operator()(C & c) const
179 {
180 bgi::detail::rtree::utilities::print(std::cout, c.tree);
181 }
182 };
183 template <typename Cont>
print_tree(Cont const & cont)184 inline void print_tree(Cont const& cont)
185 {
186 return boost::apply_visitor(print_tree_v(), cont);
187 }
188
189 // globals used in querying
190
191 size_t found_count = 0;
192 size_t count = 5;
193
194 P search_point;
195 B search_box;
196 R search_ring;
197 Poly search_poly;
198 MPoly search_multi_poly;
199 S search_segment;
200 LS search_linestring;
201 LS search_path;
202
203 enum query_mode_type {
204 qm_knn, qm_knnb, qm_knns, qm_c, qm_d, qm_i, qm_o, qm_w, qm_nc, qm_nd, qm_ni, qm_no, qm_nw, qm_all, qm_ri, qm_pi, qm_mpi, qm_si, qm_lsi, qm_path
205 } query_mode = qm_knn;
206
207 bool search_valid = false;
208
209 // various queries
210
query_knn()211 void query_knn()
212 {
213 float x = ( rand() % 1000 ) / 10.0f;
214 float y = ( rand() % 1000 ) / 10.0f;
215
216 if ( query_mode == qm_knn )
217 {
218 search_point = P(x, y);
219 found_count = query(cont, bgi::nearest(search_point, count));
220 }
221 else if ( query_mode == qm_knnb )
222 {
223 float w = 2 + ( rand() % 1000 ) / 500.0f;
224 float h = 2 + ( rand() % 1000 ) / 500.0f;
225 search_box = B(P(x - w, y - h), P(x + w, y + h));
226 found_count = query(cont, bgi::nearest(search_box, count));
227 }
228 else if ( query_mode == qm_knns )
229 {
230 int signx = rand() % 2 ? 1 : -1;
231 int signy = rand() % 2 ? 1 : -1;
232 float w = (10 + ( rand() % 1000 ) / 100.0f) * signx;
233 float h = (10 + ( rand() % 1000 ) / 100.0f) * signy;
234 search_segment = S(P(x - w, y - h), P(x + w, y + h));
235 found_count = query(cont, bgi::nearest(search_segment, count));
236 }
237 else
238 {
239 BOOST_ASSERT(false);
240 }
241
242 if ( found_count > 0 )
243 {
244 if ( query_mode == qm_knn )
245 {
246 std::cout << "search point: ";
247 bgi::detail::utilities::print_indexable(std::cout, search_point);
248 }
249 else if ( query_mode == qm_knnb )
250 {
251 std::cout << "search box: ";
252 bgi::detail::utilities::print_indexable(std::cout, search_box);
253 }
254 else if ( query_mode == qm_knns )
255 {
256 std::cout << "search segment: ";
257 bgi::detail::utilities::print_indexable(std::cout, search_segment);
258 }
259 else
260 {
261 BOOST_ASSERT(false);
262 }
263 std::cout << "\nfound: ";
264 print_result(cont);
265 }
266 else
267 std::cout << "nearest not found\n";
268 }
269
270 #ifndef ENABLE_POINTS_AND_SEGMENTS
query_path()271 void query_path()
272 {
273 float x = ( rand() % 1000 ) / 10.0f;
274 float y = ( rand() % 1000 ) / 10.0f;
275 float w = 20 + ( rand() % 1000 ) / 100.0f;
276 float h = 20 + ( rand() % 1000 ) / 100.0f;
277
278 search_path.resize(10);
279 float yy = y-h;
280 for ( int i = 0 ; i < 5 ; ++i, yy += h / 2 )
281 {
282 search_path[2 * i] = P(x-w, yy);
283 search_path[2 * i + 1] = P(x+w, yy);
284 }
285
286 found_count = query(cont, bgi::detail::path<LS>(search_path, count));
287
288 if ( found_count > 0 )
289 {
290 std::cout << "search path: ";
291 BOOST_FOREACH(P const& p, search_path)
292 bgi::detail::utilities::print_indexable(std::cout, p);
293 std::cout << "\nfound: ";
294 print_result(cont);
295 }
296 else
297 std::cout << "values on path not found\n";
298 }
299 #endif
300
301 template <typename Predicate>
query()302 void query()
303 {
304 if ( query_mode != qm_all )
305 {
306 float x = ( rand() % 1000 ) / 10.0f;
307 float y = ( rand() % 1000 ) / 10.0f;
308 float w = 10 + ( rand() % 1000 ) / 100.0f;
309 float h = 10 + ( rand() % 1000 ) / 100.0f;
310
311 search_box = B(P(x - w, y - h), P(x + w, y + h));
312 }
313 else
314 {
315 search_box = bounds(cont);
316 }
317
318 found_count = query(cont, Predicate(search_box));
319
320 if ( found_count > 0 )
321 {
322 std::cout << "search box: ";
323 bgi::detail::utilities::print_indexable(std::cout, search_box);
324 std::cout << "\nfound: ";
325 print_result(cont);
326 }
327 else
328 std::cout << "boxes not found\n";
329 }
330
331 template <typename Predicate>
query_ring()332 void query_ring()
333 {
334 float x = ( rand() % 1000 ) / 10.0f;
335 float y = ( rand() % 1000 ) / 10.0f;
336 float w = 10 + ( rand() % 1000 ) / 100.0f;
337 float h = 10 + ( rand() % 1000 ) / 100.0f;
338
339 search_ring.clear();
340 search_ring.push_back(P(x - w, y - h));
341 search_ring.push_back(P(x - w/2, y - h));
342 search_ring.push_back(P(x, y - 3*h/2));
343 search_ring.push_back(P(x + w/2, y - h));
344 search_ring.push_back(P(x + w, y - h));
345 search_ring.push_back(P(x + w, y - h/2));
346 search_ring.push_back(P(x + 3*w/2, y));
347 search_ring.push_back(P(x + w, y + h/2));
348 search_ring.push_back(P(x + w, y + h));
349 search_ring.push_back(P(x + w/2, y + h));
350 search_ring.push_back(P(x, y + 3*h/2));
351 search_ring.push_back(P(x - w/2, y + h));
352 search_ring.push_back(P(x - w, y + h));
353 search_ring.push_back(P(x - w, y + h/2));
354 search_ring.push_back(P(x - 3*w/2, y));
355 search_ring.push_back(P(x - w, y - h/2));
356 search_ring.push_back(P(x - w, y - h));
357
358 found_count = query(cont, Predicate(search_ring));
359
360 if ( found_count > 0 )
361 {
362 std::cout << "search ring: ";
363 BOOST_FOREACH(P const& p, search_ring)
364 {
365 bgi::detail::utilities::print_indexable(std::cout, p);
366 std::cout << ' ';
367 }
368 std::cout << "\nfound: ";
369 print_result(cont);
370 }
371 else
372 std::cout << "boxes not found\n";
373 }
374
375 template <typename Predicate>
query_poly()376 void query_poly()
377 {
378 float x = ( rand() % 1000 ) / 10.0f;
379 float y = ( rand() % 1000 ) / 10.0f;
380 float w = 10 + ( rand() % 1000 ) / 100.0f;
381 float h = 10 + ( rand() % 1000 ) / 100.0f;
382
383 search_poly.clear();
384 search_poly.outer().push_back(P(x - w, y - h));
385 search_poly.outer().push_back(P(x - w/2, y - h));
386 search_poly.outer().push_back(P(x, y - 3*h/2));
387 search_poly.outer().push_back(P(x + w/2, y - h));
388 search_poly.outer().push_back(P(x + w, y - h));
389 search_poly.outer().push_back(P(x + w, y - h/2));
390 search_poly.outer().push_back(P(x + 3*w/2, y));
391 search_poly.outer().push_back(P(x + w, y + h/2));
392 search_poly.outer().push_back(P(x + w, y + h));
393 search_poly.outer().push_back(P(x + w/2, y + h));
394 search_poly.outer().push_back(P(x, y + 3*h/2));
395 search_poly.outer().push_back(P(x - w/2, y + h));
396 search_poly.outer().push_back(P(x - w, y + h));
397 search_poly.outer().push_back(P(x - w, y + h/2));
398 search_poly.outer().push_back(P(x - 3*w/2, y));
399 search_poly.outer().push_back(P(x - w, y - h/2));
400 search_poly.outer().push_back(P(x - w, y - h));
401
402 search_poly.inners().push_back(Poly::ring_type());
403 search_poly.inners()[0].push_back(P(x - w/2, y - h/2));
404 search_poly.inners()[0].push_back(P(x + w/2, y - h/2));
405 search_poly.inners()[0].push_back(P(x + w/2, y + h/2));
406 search_poly.inners()[0].push_back(P(x - w/2, y + h/2));
407 search_poly.inners()[0].push_back(P(x - w/2, y - h/2));
408
409 found_count = query(cont, Predicate(search_poly));
410
411 if ( found_count > 0 )
412 {
413 std::cout << "search poly outer: ";
414 BOOST_FOREACH(P const& p, search_poly.outer())
415 {
416 bgi::detail::utilities::print_indexable(std::cout, p);
417 std::cout << ' ';
418 }
419 std::cout << "\nfound: ";
420 print_result(cont);
421 }
422 else
423 std::cout << "boxes not found\n";
424 }
425
426 template <typename Predicate>
query_multi_poly()427 void query_multi_poly()
428 {
429 float x = ( rand() % 1000 ) / 10.0f;
430 float y = ( rand() % 1000 ) / 10.0f;
431 float w = 10 + ( rand() % 1000 ) / 100.0f;
432 float h = 10 + ( rand() % 1000 ) / 100.0f;
433
434 search_multi_poly.clear();
435
436 search_multi_poly.push_back(Poly());
437 search_multi_poly[0].outer().push_back(P(x - w, y - h));
438 search_multi_poly[0].outer().push_back(P(x - w/2, y - h));
439 search_multi_poly[0].outer().push_back(P(x, y - 3*h/2));
440 search_multi_poly[0].outer().push_back(P(x + w/2, y - h));
441 search_multi_poly[0].outer().push_back(P(x + w, y - h));
442 search_multi_poly[0].outer().push_back(P(x + w, y - h/2));
443 search_multi_poly[0].outer().push_back(P(x + 3*w/2, y));
444 search_multi_poly[0].outer().push_back(P(x + w, y + h/2));
445 search_multi_poly[0].outer().push_back(P(x + w, y + h));
446 search_multi_poly[0].outer().push_back(P(x + w/2, y + h));
447 search_multi_poly[0].outer().push_back(P(x, y + 3*h/2));
448 search_multi_poly[0].outer().push_back(P(x - w/2, y + h));
449 search_multi_poly[0].outer().push_back(P(x - w, y + h));
450 search_multi_poly[0].outer().push_back(P(x - w, y + h/2));
451 search_multi_poly[0].outer().push_back(P(x - 3*w/2, y));
452 search_multi_poly[0].outer().push_back(P(x - w, y - h/2));
453 search_multi_poly[0].outer().push_back(P(x - w, y - h));
454
455 search_multi_poly[0].inners().push_back(Poly::ring_type());
456 search_multi_poly[0].inners()[0].push_back(P(x - w/2, y - h/2));
457 search_multi_poly[0].inners()[0].push_back(P(x + w/2, y - h/2));
458 search_multi_poly[0].inners()[0].push_back(P(x + w/2, y + h/2));
459 search_multi_poly[0].inners()[0].push_back(P(x - w/2, y + h/2));
460 search_multi_poly[0].inners()[0].push_back(P(x - w/2, y - h/2));
461
462 search_multi_poly.push_back(Poly());
463 search_multi_poly[1].outer().push_back(P(x - 2*w, y - 2*h));
464 search_multi_poly[1].outer().push_back(P(x - 6*w/5, y - 2*h));
465 search_multi_poly[1].outer().push_back(P(x - 6*w/5, y - 6*h/5));
466 search_multi_poly[1].outer().push_back(P(x - 2*w, y - 6*h/5));
467 search_multi_poly[1].outer().push_back(P(x - 2*w, y - 2*h));
468
469 search_multi_poly.push_back(Poly());
470 search_multi_poly[2].outer().push_back(P(x + 6*w/5, y + 6*h/5));
471 search_multi_poly[2].outer().push_back(P(x + 2*w, y + 6*h/5));
472 search_multi_poly[2].outer().push_back(P(x + 2*w, y + 2*h));
473 search_multi_poly[2].outer().push_back(P(x + 6*w/5, y + 2*h));
474 search_multi_poly[2].outer().push_back(P(x + 6*w/5, y + 6*h/5));
475
476 found_count = query(cont, Predicate(search_multi_poly));
477
478 if ( found_count > 0 )
479 {
480 std::cout << "search multi_poly[0] outer: ";
481 BOOST_FOREACH(P const& p, search_multi_poly[0].outer())
482 {
483 bgi::detail::utilities::print_indexable(std::cout, p);
484 std::cout << ' ';
485 }
486 std::cout << "\nfound: ";
487 print_result(cont);
488 }
489 else
490 std::cout << "boxes not found\n";
491 }
492
493 template <typename Predicate>
query_segment()494 void query_segment()
495 {
496 float x = ( rand() % 1000 ) / 10.0f;
497 float y = ( rand() % 1000 ) / 10.0f;
498 float w = 10.0f - ( rand() % 1000 ) / 50.0f;
499 float h = 10.0f - ( rand() % 1000 ) / 50.0f;
500 w += 0 <= w ? 10 : -10;
501 h += 0 <= h ? 10 : -10;
502
503 boost::geometry::set<0, 0>(search_segment, x - w);
504 boost::geometry::set<0, 1>(search_segment, y - h);
505 boost::geometry::set<1, 0>(search_segment, x + w);
506 boost::geometry::set<1, 1>(search_segment, y + h);
507
508 found_count = query(cont, Predicate(search_segment));
509
510 if ( found_count > 0 )
511 {
512 std::cout << "search segment: ";
513 bgi::detail::utilities::print_indexable(std::cout, P(x-w, y-h));
514 bgi::detail::utilities::print_indexable(std::cout, P(x+w, y+h));
515
516 std::cout << "\nfound: ";
517 print_result(cont);
518 }
519 else
520 std::cout << "boxes not found\n";
521 }
522
523 template <typename Predicate>
query_linestring()524 void query_linestring()
525 {
526 float x = ( rand() % 1000 ) / 10.0f;
527 float y = ( rand() % 1000 ) / 10.0f;
528 float w = 10 + ( rand() % 1000 ) / 100.0f;
529 float h = 10 + ( rand() % 1000 ) / 100.0f;
530
531 search_linestring.clear();
532 float a = 0;
533 float d = 0;
534 for ( size_t i = 0 ; i < 300 ; ++i, a += 0.05, d += 0.005 )
535 {
536 float xx = x + w * d * ::cos(a);
537 float yy = y + h * d * ::sin(a);
538 search_linestring.push_back(P(xx, yy));
539 }
540
541 found_count = query(cont, Predicate(search_linestring));
542
543 if ( found_count > 0 )
544 {
545 std::cout << "search linestring: ";
546 BOOST_FOREACH(P const& p, search_linestring)
547 {
548 bgi::detail::utilities::print_indexable(std::cout, p);
549 std::cout << ' ';
550 }
551 std::cout << "\nfound: ";
552 print_result(cont);
553 }
554 else
555 std::cout << "boxes not found\n";
556 }
557
558 // the function running the correct query based on the query_mode
559
search()560 void search()
561 {
562 namespace d = bgi::detail;
563
564 if ( query_mode == qm_knn || query_mode == qm_knnb || query_mode == qm_knns )
565 query_knn();
566 else if ( query_mode == qm_d )
567 query< d::spatial_predicate<B, d::disjoint_tag, false> >();
568 else if ( query_mode == qm_i )
569 query< d::spatial_predicate<B, d::intersects_tag, false> >();
570 else if ( query_mode == qm_nd )
571 query< d::spatial_predicate<B, d::disjoint_tag, true> >();
572 else if ( query_mode == qm_ni )
573 query< d::spatial_predicate<B, d::intersects_tag, true> >();
574 else if ( query_mode == qm_all )
575 query< d::spatial_predicate<B, d::intersects_tag, false> >();
576 #ifdef ENABLE_POINTS_AND_SEGMENTS
577 else
578 std::cout << "query disabled\n";
579 #else
580 else if ( query_mode == qm_c )
581 query< d::spatial_predicate<B, d::covered_by_tag, false> >();
582 else if ( query_mode == qm_o )
583 query< d::spatial_predicate<B, d::overlaps_tag, false> >();
584 else if ( query_mode == qm_w )
585 query< d::spatial_predicate<B, d::within_tag, false> >();
586 else if ( query_mode == qm_nc )
587 query< d::spatial_predicate<B, d::covered_by_tag, true> >();
588 else if ( query_mode == qm_no )
589 query< d::spatial_predicate<B, d::overlaps_tag, true> >();
590 else if ( query_mode == qm_nw )
591 query< d::spatial_predicate<B, d::within_tag, true> >();
592 else if ( query_mode == qm_ri )
593 query_ring< d::spatial_predicate<R, d::intersects_tag, false> >();
594 else if ( query_mode == qm_pi )
595 query_poly< d::spatial_predicate<Poly, d::intersects_tag, false> >();
596 else if ( query_mode == qm_mpi )
597 query_multi_poly< d::spatial_predicate<MPoly, d::intersects_tag, false> >();
598 else if ( query_mode == qm_si )
599 query_segment< d::spatial_predicate<S, d::intersects_tag, false> >();
600 else if ( query_mode == qm_lsi )
601 query_linestring< d::spatial_predicate<LS, d::intersects_tag, false> >();
602 else if ( query_mode == qm_path )
603 query_path();
604 #endif
605
606 search_valid = true;
607 }
608
609 // various drawing functions
610
draw_point(P const & p)611 void draw_point(P const& p)
612 {
613 float x = boost::geometry::get<0>(p);
614 float y = boost::geometry::get<1>(p);
615 float z = depth(cont);
616
617 glBegin(GL_QUADS);
618 glVertex3f(x+1, y, z);
619 glVertex3f(x, y+1, z);
620 glVertex3f(x-1, y, z);
621 glVertex3f(x, y-1, z);
622 glEnd();
623 }
624
draw_knn_area(float min_distance,float max_distance)625 void draw_knn_area(float min_distance, float max_distance)
626 {
627 float x = boost::geometry::get<0>(search_point);
628 float y = boost::geometry::get<1>(search_point);
629 float z = depth(cont);
630
631 draw_point(search_point);
632
633 // search min circle
634
635 glBegin(GL_LINE_LOOP);
636 for(float a = 0 ; a < 3.14158f * 2 ; a += 3.14158f / 180)
637 glVertex3f(x + min_distance * ::cos(a), y + min_distance * ::sin(a), z);
638 glEnd();
639
640 // search max circle
641
642 glBegin(GL_LINE_LOOP);
643 for(float a = 0 ; a < 3.14158f * 2 ; a += 3.14158f / 180)
644 glVertex3f(x + max_distance * ::cos(a), y + max_distance * ::sin(a), z);
645 glEnd();
646 }
647
draw_linestring(LS const & ls)648 void draw_linestring(LS const& ls)
649 {
650 glBegin(GL_LINE_STRIP);
651
652 BOOST_FOREACH(P const& p, ls)
653 {
654 float x = boost::geometry::get<0>(p);
655 float y = boost::geometry::get<1>(p);
656 float z = depth(cont);
657 glVertex3f(x, y, z);
658 }
659
660 glEnd();
661 }
662
draw_segment(S const & s)663 void draw_segment(S const& s)
664 {
665 float x1 = boost::geometry::get<0, 0>(s);
666 float y1 = boost::geometry::get<0, 1>(s);
667 float x2 = boost::geometry::get<1, 0>(s);
668 float y2 = boost::geometry::get<1, 1>(s);
669 float z = depth(cont);
670
671 glBegin(GL_LINES);
672 glVertex3f(x1, y1, z);
673 glVertex3f(x2, y2, z);
674 glEnd();
675 }
676
677 template <typename Box>
draw_box(Box const & box)678 void draw_box(Box const& box)
679 {
680 float x1 = boost::geometry::get<bg::min_corner, 0>(box);
681 float y1 = boost::geometry::get<bg::min_corner, 1>(box);
682 float x2 = boost::geometry::get<bg::max_corner, 0>(box);
683 float y2 = boost::geometry::get<bg::max_corner, 1>(box);
684 float z = depth(cont);
685
686 // search box
687 glBegin(GL_LINE_LOOP);
688 glVertex3f(x1, y1, z);
689 glVertex3f(x2, y1, z);
690 glVertex3f(x2, y2, z);
691 glVertex3f(x1, y2, z);
692 glEnd();
693 }
694
695 template <typename Range>
draw_ring(Range const & range)696 void draw_ring(Range const& range)
697 {
698 float z = depth(cont);
699
700 // search box
701 glBegin(GL_LINE_LOOP);
702
703 BOOST_FOREACH(P const& p, range)
704 {
705 float x = boost::geometry::get<0>(p);
706 float y = boost::geometry::get<1>(p);
707
708 glVertex3f(x, y, z);
709 }
710 glEnd();
711 }
712
713 template <typename Polygon>
draw_polygon(Polygon const & polygon)714 void draw_polygon(Polygon const& polygon)
715 {
716 draw_ring(polygon.outer());
717 BOOST_FOREACH(Poly::ring_type const& r, polygon.inners())
718 draw_ring(r);
719 }
720
721 template <typename MultiPolygon>
draw_multi_polygon(MultiPolygon const & multi_polygon)722 void draw_multi_polygon(MultiPolygon const& multi_polygon)
723 {
724 BOOST_FOREACH(Poly const& p, multi_polygon)
725 draw_polygon(p);
726 }
727
728 // render the scene -> tree, if searching data available also the query geometry and result
729
render_scene(void)730 void render_scene(void)
731 {
732 glClear(GL_COLOR_BUFFER_BIT);
733
734 draw_tree(cont);
735
736 if ( search_valid )
737 {
738 glColor3f(1.0f, 0.25f, 0.0f);
739
740 if ( query_mode == qm_knn )
741 draw_knn_area(0, 0);
742 else if ( query_mode == qm_knnb )
743 draw_box(search_box);
744 else if ( query_mode == qm_knns )
745 draw_segment(search_segment);
746 else if ( query_mode == qm_ri )
747 draw_ring(search_ring);
748 else if ( query_mode == qm_pi )
749 draw_polygon(search_poly);
750 else if ( query_mode == qm_mpi )
751 draw_multi_polygon(search_multi_poly);
752 else if ( query_mode == qm_si )
753 draw_segment(search_segment);
754 else if ( query_mode == qm_lsi )
755 draw_linestring(search_linestring);
756 else if ( query_mode == qm_path )
757 draw_linestring(search_path);
758 else
759 draw_box(search_box);
760
761 glColor3f(1.0f, 0.5f, 0.0f);
762
763 draw_result(cont);
764 }
765
766 glFlush();
767 }
768
resize(int w,int h)769 void resize(int w, int h)
770 {
771 if ( h == 0 )
772 h = 1;
773
774 //float ratio = float(w) / h;
775
776 glMatrixMode(GL_PROJECTION);
777 glLoadIdentity();
778
779 glViewport(0, 0, w, h);
780
781 //gluPerspective(45, ratio, 1, 1000);
782 glOrtho(-150, 150, -150, 150, -150, 150);
783 glMatrixMode(GL_MODELVIEW);
784 glLoadIdentity();
785 /*gluLookAt(
786 120.0f, 120.0f, 120.0f,
787 50.0f, 50.0f, -1.0f,
788 0.0f, 1.0f, 0.0f);*/
789 gluLookAt(
790 50.0f, 50.0f, 75.0f,
791 50.0f, 50.0f, -1.0f,
792 0.0f, 1.0f, 0.0f);
793
794 glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
795 glLineWidth(1.5f);
796
797 srand(1);
798 }
799
800 // randomize various indexables
801
rand_val(B & b)802 inline void rand_val(B & b)
803 {
804 float x = ( rand() % 100 );
805 float y = ( rand() % 100 );
806 float w = ( rand() % 2 ) + 1;
807 float h = ( rand() % 2 ) + 1;
808 b = B(P(x - w, y - h),P(x + w, y + h));
809 }
rand_val(P & p)810 inline void rand_val(P & p)
811 {
812 float x = ( rand() % 100 );
813 float y = ( rand() % 100 );
814 p = P(x, y);
815 }
rand_val(S & s)816 inline void rand_val(S & s)
817 {
818 float x = ( rand() % 100 );
819 float y = ( rand() % 100 );
820 float w = ( rand() % 2 + 1) * (rand() % 2 ? 1.0f : -1.0f);
821 float h = ( rand() % 2 + 1) * (rand() % 2 ? 1.0f : -1.0f);
822 s = S(P(x - w, y - h),P(x + w, y + h));
823 }
824
825 // more higher-level visitors
826
827 struct insert_random_value_v : boost::static_visitor<>
828 {
829 template <typename V>
operator ()insert_random_value_v830 void operator()(containers<V> & c) const
831 {
832 V v;
833 rand_val(v);
834
835 boost::geometry::index::insert(c.tree, v);
836 c.values.push_back(v);
837
838 std::cout << "inserted: ";
839 bgi::detail::utilities::print_indexable(std::cout, v);
840 std::cout << '\n';
841
842 std::cout << ( bgi::detail::rtree::utilities::are_boxes_ok(c.tree) ? "boxes OK\n" : "WRONG BOXES!\n" );
843 std::cout << ( bgi::detail::rtree::utilities::are_levels_ok(c.tree) ? "levels OK\n" : "WRONG LEVELS!\n" );
844 std::cout << "\n";
845 }
846 };
847 template <typename Cont>
insert_random_value(Cont & cont)848 inline void insert_random_value(Cont & cont)
849 {
850 return boost::apply_visitor(insert_random_value_v(), cont);
851 }
852
853 struct remove_random_value_v : boost::static_visitor<>
854 {
855 template <typename V>
operator ()remove_random_value_v856 void operator()(containers<V> & c) const
857 {
858 if ( c.values.empty() )
859 return;
860
861 size_t i = rand() % c.values.size();
862 V v = c.values[i];
863
864 c.tree.remove(v);
865 c.values.erase(c.values.begin() + i);
866
867 std::cout << "removed: ";
868 bgi::detail::utilities::print_indexable(std::cout, v);
869 std::cout << '\n';
870
871 std::cout << ( bgi::detail::rtree::utilities::are_boxes_ok(c.tree) ? "boxes OK\n" : "WRONG BOXES!\n" );
872 std::cout << ( bgi::detail::rtree::utilities::are_levels_ok(c.tree) ? "levels OK\n" : "WRONG LEVELS!\n" );
873 std::cout << "\n";
874 }
875 };
876 template <typename Cont>
remove_random_value(Cont & cont)877 inline void remove_random_value(Cont & cont)
878 {
879 return boost::apply_visitor(remove_random_value_v(), cont);
880 }
881
882 // handle mouse input
883
mouse(int button,int state,int,int)884 void mouse(int button, int state, int /*x*/, int /*y*/)
885 {
886 if ( button == GLUT_LEFT_BUTTON && state == GLUT_DOWN )
887 {
888 insert_random_value(cont);
889 search_valid = false;
890 }
891 else if ( button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN )
892 {
893 remove_random_value(cont);
894 search_valid = false;
895 }
896 else if ( button == GLUT_MIDDLE_BUTTON && state == GLUT_DOWN )
897 {
898 search();
899 }
900
901 glutPostRedisplay();
902 }
903
904 // more higher-level visitors
905
906 struct insert_random_values_v : boost::static_visitor<>
907 {
908 template <typename V>
operator ()insert_random_values_v909 void operator()(containers<V> & c) const
910 {
911 for ( size_t i = 0 ; i < 35 ; ++i )
912 {
913 V v;
914 rand_val(v);
915
916 c.tree.insert(v);
917 c.values.push_back(v);
918
919 std::cout << "inserted: ";
920 bgi::detail::utilities::print_indexable(std::cout, v);
921 std::cout << '\n';
922 }
923
924 std::cout << ( bgi::detail::rtree::utilities::are_boxes_ok(c.tree) ? "boxes OK\n" : "WRONG BOXES!\n" );
925 std::cout << ( bgi::detail::rtree::utilities::are_levels_ok(c.tree) ? "levels OK\n" : "WRONG LEVELS!\n" );
926 std::cout << "\n";
927 }
928 };
929 template <typename Cont>
insert_random_values(Cont & cont)930 inline void insert_random_values(Cont & cont)
931 {
932 return boost::apply_visitor(insert_random_values_v(), cont);
933 }
934
935 struct bulk_insert_random_values_v : boost::static_visitor<>
936 {
937 template <typename V>
operator ()bulk_insert_random_values_v938 void operator()(containers<V> & c) const
939 {
940 c.values.clear();
941
942 for ( size_t i = 0 ; i < 35 ; ++i )
943 {
944 V v;
945 rand_val(v);
946
947 c.values.push_back(v);
948
949 std::cout << "inserted: ";
950 bgi::detail::utilities::print_indexable(std::cout, v);
951 std::cout << '\n';
952 }
953
954 create(c.tree, c.values);
955
956 std::cout << ( bgi::detail::rtree::utilities::are_boxes_ok(c.tree) ? "boxes OK\n" : "WRONG BOXES!\n" );
957 std::cout << ( bgi::detail::rtree::utilities::are_levels_ok(c.tree) ? "levels OK\n" : "WRONG LEVELS!\n" );
958 std::cout << "\n";
959 }
960
961 template <typename Tree, typename Values>
createbulk_insert_random_values_v962 void create(Tree & tree, Values const& values) const
963 {
964 Tree t(values);
965 tree = boost::move(t);
966 }
967 };
968 template <typename Cont>
bulk_insert_random_values(Cont & cont)969 inline void bulk_insert_random_values(Cont & cont)
970 {
971 return boost::apply_visitor(bulk_insert_random_values_v(), cont);
972 }
973
974 // handle keyboard input
975
976 std::string current_line;
977
keyboard(unsigned char key,int,int)978 void keyboard(unsigned char key, int /*x*/, int /*y*/)
979 {
980 if ( key == '\r' || key == '\n' )
981 {
982 if ( current_line == "storeb" )
983 {
984 cont = containers<B>();
985 glutPostRedisplay();
986 }
987 #ifdef ENABLE_POINTS_AND_SEGMENTS
988 else if ( current_line == "storep" )
989 {
990 cont = containers<P>();
991 glutPostRedisplay();
992 }
993 else if ( current_line == "stores" )
994 {
995 cont = containers<S>();
996 glutPostRedisplay();
997 }
998 #endif
999 else if ( current_line == "t" )
1000 {
1001 std::cout << "\n";
1002 print_tree(cont);
1003 std::cout << "\n";
1004 }
1005 else if ( current_line == "rand" )
1006 {
1007 insert_random_values(cont);
1008 search_valid = false;
1009
1010 glutPostRedisplay();
1011 }
1012 else if ( current_line == "bulk" )
1013 {
1014 bulk_insert_random_values(cont);
1015 search_valid = false;
1016
1017 glutPostRedisplay();
1018 }
1019 else
1020 {
1021 if ( current_line == "knn" )
1022 query_mode = qm_knn;
1023 else if ( current_line == "knnb" )
1024 query_mode = qm_knnb;
1025 else if ( current_line == "knns" )
1026 query_mode = qm_knns;
1027 else if ( current_line == "c" )
1028 query_mode = qm_c;
1029 else if ( current_line == "d" )
1030 query_mode = qm_d;
1031 else if ( current_line == "i" )
1032 query_mode = qm_i;
1033 else if ( current_line == "o" )
1034 query_mode = qm_o;
1035 else if ( current_line == "w" )
1036 query_mode = qm_w;
1037 else if ( current_line == "nc" )
1038 query_mode = qm_nc;
1039 else if ( current_line == "nd" )
1040 query_mode = qm_nd;
1041 else if ( current_line == "ni" )
1042 query_mode = qm_ni;
1043 else if ( current_line == "no" )
1044 query_mode = qm_no;
1045 else if ( current_line == "nw" )
1046 query_mode = qm_nw;
1047 else if ( current_line == "all" )
1048 query_mode = qm_all;
1049 else if ( current_line == "ri" )
1050 query_mode = qm_ri;
1051 else if ( current_line == "pi" )
1052 query_mode = qm_pi;
1053 else if ( current_line == "mpi" )
1054 query_mode = qm_mpi;
1055 else if ( current_line == "si" )
1056 query_mode = qm_si;
1057 else if ( current_line == "lsi" )
1058 query_mode = qm_lsi;
1059 else if ( current_line == "path" )
1060 query_mode = qm_path;
1061
1062 search();
1063 glutPostRedisplay();
1064 }
1065
1066 current_line.clear();
1067 std::cout << '\n';
1068 }
1069 else
1070 {
1071 current_line += key;
1072 std::cout << key;
1073 }
1074 }
1075
1076 // main function
1077
main(int argc,char ** argv)1078 int main(int argc, char **argv)
1079 {
1080 glutInit(&argc, argv);
1081 glutInitDisplayMode(GLUT_DEPTH | GLUT_SINGLE | GLUT_RGBA);
1082 glutInitWindowPosition(100,100);
1083 glutInitWindowSize(600, 600);
1084 glutCreateWindow("boost::geometry::index::rtree GLUT test");
1085
1086 glutDisplayFunc(render_scene);
1087 glutReshapeFunc(resize);
1088 glutMouseFunc(mouse);
1089 glutKeyboardFunc(keyboard);
1090
1091 glutMainLoop();
1092
1093 return 0;
1094 }
1095