• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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