blob: 2c5f5740bd16259818087ae4f1f4cef9488cc00f [file] [log] [blame]
// Boost.Geometry Index
// OpenGL visualization
// Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland.
// 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)
#include <GL/glut.h>
#include <boost/foreach.hpp>
#include <boost/geometry.hpp>
#include <boost/geometry/index/rtree.hpp>
#include <boost/geometry/geometries/linestring.hpp>
#include <boost/geometry/geometries/segment.hpp>
#include <boost/geometry/geometries/ring.hpp>
#include <boost/geometry/geometries/polygon.hpp>
#include <boost/geometry/geometries/multi_polygon.hpp>
#include <boost/geometry/index/detail/rtree/utilities/gl_draw.hpp>
#include <boost/geometry/index/detail/rtree/utilities/print.hpp>
#include <boost/geometry/index/detail/rtree/utilities/are_boxes_ok.hpp>
#include <boost/geometry/index/detail/rtree/utilities/are_levels_ok.hpp>
#include <boost/geometry/index/detail/rtree/utilities/statistics.hpp>
#include <boost/variant.hpp>
#define ENABLE_POINTS_AND_SEGMENTS
namespace bg = boost::geometry;
namespace bgi = bg::index;
// used types
typedef bg::model::point<float, 2, boost::geometry::cs::cartesian> P;
typedef bg::model::box<P> B;
typedef bg::model::linestring<P> LS;
typedef bg::model::segment<P> S;
typedef bg::model::ring<P> R;
typedef bg::model::polygon<P> Poly;
typedef bg::model::multi_polygon<Poly> MPoly;
// containers variant
template <typename V>
struct containers
{
containers & operator=(containers const& c)
{
tree = c.tree;
values = c.values;
result = c.result;
return *this;
}
bgi::rtree< V, bgi::rstar<4, 2> > tree;
std::vector<V> values;
std::vector<V> result;
};
boost::variant<
containers<B>
#ifdef ENABLE_POINTS_AND_SEGMENTS
, containers<P>
, containers<S>
#endif
> cont;
// visitors
template <typename Pred>
struct query_v : boost::static_visitor<size_t>
{
Pred m_pred;
query_v(Pred const& pred) : m_pred(pred) {}
template <typename C>
size_t operator()(C & c) const
{
c.result.clear();
return c.tree.query(m_pred, std::back_inserter(c.result));
}
};
template <typename Cont, typename Pred>
inline size_t query(Cont & cont, Pred const& pred)
{
return boost::apply_visitor(query_v<Pred>(pred), cont);
}
struct print_result_v : boost::static_visitor<>
{
template <typename C>
void operator()(C & c) const
{
for ( size_t i = 0 ; i < c.result.size() ; ++i )
{
bgi::detail::utilities::print_indexable(std::cout, c.result[i]);
std::cout << '\n';
}
}
};
template <typename Cont>
inline void print_result(Cont const& cont)
{
boost::apply_visitor(print_result_v(), cont);
}
struct bounds_v : boost::static_visitor<B>
{
template <typename C>
B operator()(C & c) const
{
return c.tree.bounds();
}
};
template <typename Cont>
inline B bounds(Cont const& cont)
{
return boost::apply_visitor(bounds_v(), cont);
}
struct depth_v : boost::static_visitor<size_t>
{
template <typename C>
size_t operator()(C & c) const
{
return get(c.tree);
}
template <typename RTree>
static size_t get(RTree const& t)
{
return bgi::detail::rtree::utilities::view<RTree>(t).depth();
}
};
template <typename Cont>
inline size_t depth(Cont const& cont)
{
return boost::apply_visitor(depth_v(), cont);
}
struct draw_tree_v : boost::static_visitor<>
{
template <typename C>
void operator()(C & c) const
{
bgi::detail::rtree::utilities::gl_draw(c.tree);
}
};
template <typename Cont>
inline void draw_tree(Cont const& cont)
{
return boost::apply_visitor(draw_tree_v(), cont);
}
struct draw_result_v : boost::static_visitor<>
{
template <typename C>
void operator()(C & c) const
{
for ( size_t i = 0 ; i < c.result.size() ; ++i )
{
bgi::detail::utilities::gl_draw_indexable(c.result[i], depth_v::get(c.tree));
}
}
};
template <typename Cont>
inline void draw_result(Cont const& cont)
{
return boost::apply_visitor(draw_result_v(), cont);
}
struct print_tree_v : boost::static_visitor<>
{
template <typename C>
void operator()(C & c) const
{
bgi::detail::rtree::utilities::print(std::cout, c.tree);
}
};
template <typename Cont>
inline void print_tree(Cont const& cont)
{
return boost::apply_visitor(print_tree_v(), cont);
}
// globals used in querying
size_t found_count = 0;
size_t count = 5;
P search_point;
B search_box;
R search_ring;
Poly search_poly;
MPoly search_multi_poly;
S search_segment;
LS search_linestring;
LS search_path;
enum query_mode_type {
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
} query_mode = qm_knn;
bool search_valid = false;
// various queries
void query_knn()
{
float x = ( rand() % 1000 ) / 10.0f;
float y = ( rand() % 1000 ) / 10.0f;
if ( query_mode == qm_knn )
{
search_point = P(x, y);
found_count = query(cont, bgi::nearest(search_point, count));
}
else if ( query_mode == qm_knnb )
{
float w = 2 + ( rand() % 1000 ) / 500.0f;
float h = 2 + ( rand() % 1000 ) / 500.0f;
search_box = B(P(x - w, y - h), P(x + w, y + h));
found_count = query(cont, bgi::nearest(search_box, count));
}
else if ( query_mode == qm_knns )
{
int signx = rand() % 2 ? 1 : -1;
int signy = rand() % 2 ? 1 : -1;
float w = (10 + ( rand() % 1000 ) / 100.0f) * signx;
float h = (10 + ( rand() % 1000 ) / 100.0f) * signy;
search_segment = S(P(x - w, y - h), P(x + w, y + h));
found_count = query(cont, bgi::nearest(search_segment, count));
}
else
{
BOOST_ASSERT(false);
}
if ( found_count > 0 )
{
if ( query_mode == qm_knn )
{
std::cout << "search point: ";
bgi::detail::utilities::print_indexable(std::cout, search_point);
}
else if ( query_mode == qm_knnb )
{
std::cout << "search box: ";
bgi::detail::utilities::print_indexable(std::cout, search_box);
}
else if ( query_mode == qm_knns )
{
std::cout << "search segment: ";
bgi::detail::utilities::print_indexable(std::cout, search_segment);
}
else
{
BOOST_ASSERT(false);
}
std::cout << "\nfound: ";
print_result(cont);
}
else
std::cout << "nearest not found\n";
}
#ifndef ENABLE_POINTS_AND_SEGMENTS
void query_path()
{
float x = ( rand() % 1000 ) / 10.0f;
float y = ( rand() % 1000 ) / 10.0f;
float w = 20 + ( rand() % 1000 ) / 100.0f;
float h = 20 + ( rand() % 1000 ) / 100.0f;
search_path.resize(10);
float yy = y-h;
for ( int i = 0 ; i < 5 ; ++i, yy += h / 2 )
{
search_path[2 * i] = P(x-w, yy);
search_path[2 * i + 1] = P(x+w, yy);
}
found_count = query(cont, bgi::detail::path<LS>(search_path, count));
if ( found_count > 0 )
{
std::cout << "search path: ";
BOOST_FOREACH(P const& p, search_path)
bgi::detail::utilities::print_indexable(std::cout, p);
std::cout << "\nfound: ";
print_result(cont);
}
else
std::cout << "values on path not found\n";
}
#endif
template <typename Predicate>
void query()
{
if ( query_mode != qm_all )
{
float x = ( rand() % 1000 ) / 10.0f;
float y = ( rand() % 1000 ) / 10.0f;
float w = 10 + ( rand() % 1000 ) / 100.0f;
float h = 10 + ( rand() % 1000 ) / 100.0f;
search_box = B(P(x - w, y - h), P(x + w, y + h));
}
else
{
search_box = bounds(cont);
}
found_count = query(cont, Predicate(search_box));
if ( found_count > 0 )
{
std::cout << "search box: ";
bgi::detail::utilities::print_indexable(std::cout, search_box);
std::cout << "\nfound: ";
print_result(cont);
}
else
std::cout << "boxes not found\n";
}
template <typename Predicate>
void query_ring()
{
float x = ( rand() % 1000 ) / 10.0f;
float y = ( rand() % 1000 ) / 10.0f;
float w = 10 + ( rand() % 1000 ) / 100.0f;
float h = 10 + ( rand() % 1000 ) / 100.0f;
search_ring.clear();
search_ring.push_back(P(x - w, y - h));
search_ring.push_back(P(x - w/2, y - h));
search_ring.push_back(P(x, y - 3*h/2));
search_ring.push_back(P(x + w/2, y - h));
search_ring.push_back(P(x + w, y - h));
search_ring.push_back(P(x + w, y - h/2));
search_ring.push_back(P(x + 3*w/2, y));
search_ring.push_back(P(x + w, y + h/2));
search_ring.push_back(P(x + w, y + h));
search_ring.push_back(P(x + w/2, y + h));
search_ring.push_back(P(x, y + 3*h/2));
search_ring.push_back(P(x - w/2, y + h));
search_ring.push_back(P(x - w, y + h));
search_ring.push_back(P(x - w, y + h/2));
search_ring.push_back(P(x - 3*w/2, y));
search_ring.push_back(P(x - w, y - h/2));
search_ring.push_back(P(x - w, y - h));
found_count = query(cont, Predicate(search_ring));
if ( found_count > 0 )
{
std::cout << "search ring: ";
BOOST_FOREACH(P const& p, search_ring)
{
bgi::detail::utilities::print_indexable(std::cout, p);
std::cout << ' ';
}
std::cout << "\nfound: ";
print_result(cont);
}
else
std::cout << "boxes not found\n";
}
template <typename Predicate>
void query_poly()
{
float x = ( rand() % 1000 ) / 10.0f;
float y = ( rand() % 1000 ) / 10.0f;
float w = 10 + ( rand() % 1000 ) / 100.0f;
float h = 10 + ( rand() % 1000 ) / 100.0f;
search_poly.clear();
search_poly.outer().push_back(P(x - w, y - h));
search_poly.outer().push_back(P(x - w/2, y - h));
search_poly.outer().push_back(P(x, y - 3*h/2));
search_poly.outer().push_back(P(x + w/2, y - h));
search_poly.outer().push_back(P(x + w, y - h));
search_poly.outer().push_back(P(x + w, y - h/2));
search_poly.outer().push_back(P(x + 3*w/2, y));
search_poly.outer().push_back(P(x + w, y + h/2));
search_poly.outer().push_back(P(x + w, y + h));
search_poly.outer().push_back(P(x + w/2, y + h));
search_poly.outer().push_back(P(x, y + 3*h/2));
search_poly.outer().push_back(P(x - w/2, y + h));
search_poly.outer().push_back(P(x - w, y + h));
search_poly.outer().push_back(P(x - w, y + h/2));
search_poly.outer().push_back(P(x - 3*w/2, y));
search_poly.outer().push_back(P(x - w, y - h/2));
search_poly.outer().push_back(P(x - w, y - h));
search_poly.inners().push_back(Poly::ring_type());
search_poly.inners()[0].push_back(P(x - w/2, y - h/2));
search_poly.inners()[0].push_back(P(x + w/2, y - h/2));
search_poly.inners()[0].push_back(P(x + w/2, y + h/2));
search_poly.inners()[0].push_back(P(x - w/2, y + h/2));
search_poly.inners()[0].push_back(P(x - w/2, y - h/2));
found_count = query(cont, Predicate(search_poly));
if ( found_count > 0 )
{
std::cout << "search poly outer: ";
BOOST_FOREACH(P const& p, search_poly.outer())
{
bgi::detail::utilities::print_indexable(std::cout, p);
std::cout << ' ';
}
std::cout << "\nfound: ";
print_result(cont);
}
else
std::cout << "boxes not found\n";
}
template <typename Predicate>
void query_multi_poly()
{
float x = ( rand() % 1000 ) / 10.0f;
float y = ( rand() % 1000 ) / 10.0f;
float w = 10 + ( rand() % 1000 ) / 100.0f;
float h = 10 + ( rand() % 1000 ) / 100.0f;
search_multi_poly.clear();
search_multi_poly.push_back(Poly());
search_multi_poly[0].outer().push_back(P(x - w, y - h));
search_multi_poly[0].outer().push_back(P(x - w/2, y - h));
search_multi_poly[0].outer().push_back(P(x, y - 3*h/2));
search_multi_poly[0].outer().push_back(P(x + w/2, y - h));
search_multi_poly[0].outer().push_back(P(x + w, y - h));
search_multi_poly[0].outer().push_back(P(x + w, y - h/2));
search_multi_poly[0].outer().push_back(P(x + 3*w/2, y));
search_multi_poly[0].outer().push_back(P(x + w, y + h/2));
search_multi_poly[0].outer().push_back(P(x + w, y + h));
search_multi_poly[0].outer().push_back(P(x + w/2, y + h));
search_multi_poly[0].outer().push_back(P(x, y + 3*h/2));
search_multi_poly[0].outer().push_back(P(x - w/2, y + h));
search_multi_poly[0].outer().push_back(P(x - w, y + h));
search_multi_poly[0].outer().push_back(P(x - w, y + h/2));
search_multi_poly[0].outer().push_back(P(x - 3*w/2, y));
search_multi_poly[0].outer().push_back(P(x - w, y - h/2));
search_multi_poly[0].outer().push_back(P(x - w, y - h));
search_multi_poly[0].inners().push_back(Poly::ring_type());
search_multi_poly[0].inners()[0].push_back(P(x - w/2, y - h/2));
search_multi_poly[0].inners()[0].push_back(P(x + w/2, y - h/2));
search_multi_poly[0].inners()[0].push_back(P(x + w/2, y + h/2));
search_multi_poly[0].inners()[0].push_back(P(x - w/2, y + h/2));
search_multi_poly[0].inners()[0].push_back(P(x - w/2, y - h/2));
search_multi_poly.push_back(Poly());
search_multi_poly[1].outer().push_back(P(x - 2*w, y - 2*h));
search_multi_poly[1].outer().push_back(P(x - 6*w/5, y - 2*h));
search_multi_poly[1].outer().push_back(P(x - 6*w/5, y - 6*h/5));
search_multi_poly[1].outer().push_back(P(x - 2*w, y - 6*h/5));
search_multi_poly[1].outer().push_back(P(x - 2*w, y - 2*h));
search_multi_poly.push_back(Poly());
search_multi_poly[2].outer().push_back(P(x + 6*w/5, y + 6*h/5));
search_multi_poly[2].outer().push_back(P(x + 2*w, y + 6*h/5));
search_multi_poly[2].outer().push_back(P(x + 2*w, y + 2*h));
search_multi_poly[2].outer().push_back(P(x + 6*w/5, y + 2*h));
search_multi_poly[2].outer().push_back(P(x + 6*w/5, y + 6*h/5));
found_count = query(cont, Predicate(search_multi_poly));
if ( found_count > 0 )
{
std::cout << "search multi_poly[0] outer: ";
BOOST_FOREACH(P const& p, search_multi_poly[0].outer())
{
bgi::detail::utilities::print_indexable(std::cout, p);
std::cout << ' ';
}
std::cout << "\nfound: ";
print_result(cont);
}
else
std::cout << "boxes not found\n";
}
template <typename Predicate>
void query_segment()
{
float x = ( rand() % 1000 ) / 10.0f;
float y = ( rand() % 1000 ) / 10.0f;
float w = 10.0f - ( rand() % 1000 ) / 50.0f;
float h = 10.0f - ( rand() % 1000 ) / 50.0f;
w += 0 <= w ? 10 : -10;
h += 0 <= h ? 10 : -10;
boost::geometry::set<0, 0>(search_segment, x - w);
boost::geometry::set<0, 1>(search_segment, y - h);
boost::geometry::set<1, 0>(search_segment, x + w);
boost::geometry::set<1, 1>(search_segment, y + h);
found_count = query(cont, Predicate(search_segment));
if ( found_count > 0 )
{
std::cout << "search segment: ";
bgi::detail::utilities::print_indexable(std::cout, P(x-w, y-h));
bgi::detail::utilities::print_indexable(std::cout, P(x+w, y+h));
std::cout << "\nfound: ";
print_result(cont);
}
else
std::cout << "boxes not found\n";
}
template <typename Predicate>
void query_linestring()
{
float x = ( rand() % 1000 ) / 10.0f;
float y = ( rand() % 1000 ) / 10.0f;
float w = 10 + ( rand() % 1000 ) / 100.0f;
float h = 10 + ( rand() % 1000 ) / 100.0f;
search_linestring.clear();
float a = 0;
float d = 0;
for ( size_t i = 0 ; i < 300 ; ++i, a += 0.05, d += 0.005 )
{
float xx = x + w * d * ::cos(a);
float yy = y + h * d * ::sin(a);
search_linestring.push_back(P(xx, yy));
}
found_count = query(cont, Predicate(search_linestring));
if ( found_count > 0 )
{
std::cout << "search linestring: ";
BOOST_FOREACH(P const& p, search_linestring)
{
bgi::detail::utilities::print_indexable(std::cout, p);
std::cout << ' ';
}
std::cout << "\nfound: ";
print_result(cont);
}
else
std::cout << "boxes not found\n";
}
// the function running the correct query based on the query_mode
void search()
{
namespace d = bgi::detail;
if ( query_mode == qm_knn || query_mode == qm_knnb || query_mode == qm_knns )
query_knn();
else if ( query_mode == qm_d )
query< d::spatial_predicate<B, d::disjoint_tag, false> >();
else if ( query_mode == qm_i )
query< d::spatial_predicate<B, d::intersects_tag, false> >();
else if ( query_mode == qm_nd )
query< d::spatial_predicate<B, d::disjoint_tag, true> >();
else if ( query_mode == qm_ni )
query< d::spatial_predicate<B, d::intersects_tag, true> >();
else if ( query_mode == qm_all )
query< d::spatial_predicate<B, d::intersects_tag, false> >();
#ifdef ENABLE_POINTS_AND_SEGMENTS
else
std::cout << "query disabled\n";
#else
else if ( query_mode == qm_c )
query< d::spatial_predicate<B, d::covered_by_tag, false> >();
else if ( query_mode == qm_o )
query< d::spatial_predicate<B, d::overlaps_tag, false> >();
else if ( query_mode == qm_w )
query< d::spatial_predicate<B, d::within_tag, false> >();
else if ( query_mode == qm_nc )
query< d::spatial_predicate<B, d::covered_by_tag, true> >();
else if ( query_mode == qm_no )
query< d::spatial_predicate<B, d::overlaps_tag, true> >();
else if ( query_mode == qm_nw )
query< d::spatial_predicate<B, d::within_tag, true> >();
else if ( query_mode == qm_ri )
query_ring< d::spatial_predicate<R, d::intersects_tag, false> >();
else if ( query_mode == qm_pi )
query_poly< d::spatial_predicate<Poly, d::intersects_tag, false> >();
else if ( query_mode == qm_mpi )
query_multi_poly< d::spatial_predicate<MPoly, d::intersects_tag, false> >();
else if ( query_mode == qm_si )
query_segment< d::spatial_predicate<S, d::intersects_tag, false> >();
else if ( query_mode == qm_lsi )
query_linestring< d::spatial_predicate<LS, d::intersects_tag, false> >();
else if ( query_mode == qm_path )
query_path();
#endif
search_valid = true;
}
// various drawing functions
void draw_point(P const& p)
{
float x = boost::geometry::get<0>(p);
float y = boost::geometry::get<1>(p);
float z = depth(cont);
glBegin(GL_QUADS);
glVertex3f(x+1, y, z);
glVertex3f(x, y+1, z);
glVertex3f(x-1, y, z);
glVertex3f(x, y-1, z);
glEnd();
}
void draw_knn_area(float min_distance, float max_distance)
{
float x = boost::geometry::get<0>(search_point);
float y = boost::geometry::get<1>(search_point);
float z = depth(cont);
draw_point(search_point);
// search min circle
glBegin(GL_LINE_LOOP);
for(float a = 0 ; a < 3.14158f * 2 ; a += 3.14158f / 180)
glVertex3f(x + min_distance * ::cos(a), y + min_distance * ::sin(a), z);
glEnd();
// search max circle
glBegin(GL_LINE_LOOP);
for(float a = 0 ; a < 3.14158f * 2 ; a += 3.14158f / 180)
glVertex3f(x + max_distance * ::cos(a), y + max_distance * ::sin(a), z);
glEnd();
}
void draw_linestring(LS const& ls)
{
glBegin(GL_LINE_STRIP);
BOOST_FOREACH(P const& p, ls)
{
float x = boost::geometry::get<0>(p);
float y = boost::geometry::get<1>(p);
float z = depth(cont);
glVertex3f(x, y, z);
}
glEnd();
}
void draw_segment(S const& s)
{
float x1 = boost::geometry::get<0, 0>(s);
float y1 = boost::geometry::get<0, 1>(s);
float x2 = boost::geometry::get<1, 0>(s);
float y2 = boost::geometry::get<1, 1>(s);
float z = depth(cont);
glBegin(GL_LINES);
glVertex3f(x1, y1, z);
glVertex3f(x2, y2, z);
glEnd();
}
template <typename Box>
void draw_box(Box const& box)
{
float x1 = boost::geometry::get<bg::min_corner, 0>(box);
float y1 = boost::geometry::get<bg::min_corner, 1>(box);
float x2 = boost::geometry::get<bg::max_corner, 0>(box);
float y2 = boost::geometry::get<bg::max_corner, 1>(box);
float z = depth(cont);
// search box
glBegin(GL_LINE_LOOP);
glVertex3f(x1, y1, z);
glVertex3f(x2, y1, z);
glVertex3f(x2, y2, z);
glVertex3f(x1, y2, z);
glEnd();
}
template <typename Range>
void draw_ring(Range const& range)
{
float z = depth(cont);
// search box
glBegin(GL_LINE_LOOP);
BOOST_FOREACH(P const& p, range)
{
float x = boost::geometry::get<0>(p);
float y = boost::geometry::get<1>(p);
glVertex3f(x, y, z);
}
glEnd();
}
template <typename Polygon>
void draw_polygon(Polygon const& polygon)
{
draw_ring(polygon.outer());
BOOST_FOREACH(Poly::ring_type const& r, polygon.inners())
draw_ring(r);
}
template <typename MultiPolygon>
void draw_multi_polygon(MultiPolygon const& multi_polygon)
{
BOOST_FOREACH(Poly const& p, multi_polygon)
draw_polygon(p);
}
// render the scene -> tree, if searching data available also the query geometry and result
void render_scene(void)
{
glClear(GL_COLOR_BUFFER_BIT);
draw_tree(cont);
if ( search_valid )
{
glColor3f(1.0f, 0.25f, 0.0f);
if ( query_mode == qm_knn )
draw_knn_area(0, 0);
else if ( query_mode == qm_knnb )
draw_box(search_box);
else if ( query_mode == qm_knns )
draw_segment(search_segment);
else if ( query_mode == qm_ri )
draw_ring(search_ring);
else if ( query_mode == qm_pi )
draw_polygon(search_poly);
else if ( query_mode == qm_mpi )
draw_multi_polygon(search_multi_poly);
else if ( query_mode == qm_si )
draw_segment(search_segment);
else if ( query_mode == qm_lsi )
draw_linestring(search_linestring);
else if ( query_mode == qm_path )
draw_linestring(search_path);
else
draw_box(search_box);
glColor3f(1.0f, 0.5f, 0.0f);
draw_result(cont);
}
glFlush();
}
void resize(int w, int h)
{
if ( h == 0 )
h = 1;
//float ratio = float(w) / h;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glViewport(0, 0, w, h);
//gluPerspective(45, ratio, 1, 1000);
glOrtho(-150, 150, -150, 150, -150, 150);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
/*gluLookAt(
120.0f, 120.0f, 120.0f,
50.0f, 50.0f, -1.0f,
0.0f, 1.0f, 0.0f);*/
gluLookAt(
50.0f, 50.0f, 75.0f,
50.0f, 50.0f, -1.0f,
0.0f, 1.0f, 0.0f);
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glLineWidth(1.5f);
srand(1);
}
// randomize various indexables
inline void rand_val(B & b)
{
float x = ( rand() % 100 );
float y = ( rand() % 100 );
float w = ( rand() % 2 ) + 1;
float h = ( rand() % 2 ) + 1;
b = B(P(x - w, y - h),P(x + w, y + h));
}
inline void rand_val(P & p)
{
float x = ( rand() % 100 );
float y = ( rand() % 100 );
p = P(x, y);
}
inline void rand_val(S & s)
{
float x = ( rand() % 100 );
float y = ( rand() % 100 );
float w = ( rand() % 2 + 1) * (rand() % 2 ? 1.0f : -1.0f);
float h = ( rand() % 2 + 1) * (rand() % 2 ? 1.0f : -1.0f);
s = S(P(x - w, y - h),P(x + w, y + h));
}
// more higher-level visitors
struct insert_random_value_v : boost::static_visitor<>
{
template <typename V>
void operator()(containers<V> & c) const
{
V v;
rand_val(v);
boost::geometry::index::insert(c.tree, v);
c.values.push_back(v);
std::cout << "inserted: ";
bgi::detail::utilities::print_indexable(std::cout, v);
std::cout << '\n';
std::cout << ( bgi::detail::rtree::utilities::are_boxes_ok(c.tree) ? "boxes OK\n" : "WRONG BOXES!\n" );
std::cout << ( bgi::detail::rtree::utilities::are_levels_ok(c.tree) ? "levels OK\n" : "WRONG LEVELS!\n" );
std::cout << "\n";
}
};
template <typename Cont>
inline void insert_random_value(Cont & cont)
{
return boost::apply_visitor(insert_random_value_v(), cont);
}
struct remove_random_value_v : boost::static_visitor<>
{
template <typename V>
void operator()(containers<V> & c) const
{
if ( c.values.empty() )
return;
size_t i = rand() % c.values.size();
V v = c.values[i];
c.tree.remove(v);
c.values.erase(c.values.begin() + i);
std::cout << "removed: ";
bgi::detail::utilities::print_indexable(std::cout, v);
std::cout << '\n';
std::cout << ( bgi::detail::rtree::utilities::are_boxes_ok(c.tree) ? "boxes OK\n" : "WRONG BOXES!\n" );
std::cout << ( bgi::detail::rtree::utilities::are_levels_ok(c.tree) ? "levels OK\n" : "WRONG LEVELS!\n" );
std::cout << "\n";
}
};
template <typename Cont>
inline void remove_random_value(Cont & cont)
{
return boost::apply_visitor(remove_random_value_v(), cont);
}
// handle mouse input
void mouse(int button, int state, int /*x*/, int /*y*/)
{
if ( button == GLUT_LEFT_BUTTON && state == GLUT_DOWN )
{
insert_random_value(cont);
search_valid = false;
}
else if ( button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN )
{
remove_random_value(cont);
search_valid = false;
}
else if ( button == GLUT_MIDDLE_BUTTON && state == GLUT_DOWN )
{
search();
}
glutPostRedisplay();
}
// more higher-level visitors
struct insert_random_values_v : boost::static_visitor<>
{
template <typename V>
void operator()(containers<V> & c) const
{
for ( size_t i = 0 ; i < 35 ; ++i )
{
V v;
rand_val(v);
c.tree.insert(v);
c.values.push_back(v);
std::cout << "inserted: ";
bgi::detail::utilities::print_indexable(std::cout, v);
std::cout << '\n';
}
std::cout << ( bgi::detail::rtree::utilities::are_boxes_ok(c.tree) ? "boxes OK\n" : "WRONG BOXES!\n" );
std::cout << ( bgi::detail::rtree::utilities::are_levels_ok(c.tree) ? "levels OK\n" : "WRONG LEVELS!\n" );
std::cout << "\n";
}
};
template <typename Cont>
inline void insert_random_values(Cont & cont)
{
return boost::apply_visitor(insert_random_values_v(), cont);
}
struct bulk_insert_random_values_v : boost::static_visitor<>
{
template <typename V>
void operator()(containers<V> & c) const
{
c.values.clear();
for ( size_t i = 0 ; i < 35 ; ++i )
{
V v;
rand_val(v);
c.values.push_back(v);
std::cout << "inserted: ";
bgi::detail::utilities::print_indexable(std::cout, v);
std::cout << '\n';
}
create(c.tree, c.values);
std::cout << ( bgi::detail::rtree::utilities::are_boxes_ok(c.tree) ? "boxes OK\n" : "WRONG BOXES!\n" );
std::cout << ( bgi::detail::rtree::utilities::are_levels_ok(c.tree) ? "levels OK\n" : "WRONG LEVELS!\n" );
std::cout << "\n";
}
template <typename Tree, typename Values>
void create(Tree & tree, Values const& values) const
{
Tree t(values);
tree = boost::move(t);
}
};
template <typename Cont>
inline void bulk_insert_random_values(Cont & cont)
{
return boost::apply_visitor(bulk_insert_random_values_v(), cont);
}
// handle keyboard input
std::string current_line;
void keyboard(unsigned char key, int /*x*/, int /*y*/)
{
if ( key == '\r' || key == '\n' )
{
if ( current_line == "storeb" )
{
cont = containers<B>();
glutPostRedisplay();
}
#ifdef ENABLE_POINTS_AND_SEGMENTS
else if ( current_line == "storep" )
{
cont = containers<P>();
glutPostRedisplay();
}
else if ( current_line == "stores" )
{
cont = containers<S>();
glutPostRedisplay();
}
#endif
else if ( current_line == "t" )
{
std::cout << "\n";
print_tree(cont);
std::cout << "\n";
}
else if ( current_line == "rand" )
{
insert_random_values(cont);
search_valid = false;
glutPostRedisplay();
}
else if ( current_line == "bulk" )
{
bulk_insert_random_values(cont);
search_valid = false;
glutPostRedisplay();
}
else
{
if ( current_line == "knn" )
query_mode = qm_knn;
else if ( current_line == "knnb" )
query_mode = qm_knnb;
else if ( current_line == "knns" )
query_mode = qm_knns;
else if ( current_line == "c" )
query_mode = qm_c;
else if ( current_line == "d" )
query_mode = qm_d;
else if ( current_line == "i" )
query_mode = qm_i;
else if ( current_line == "o" )
query_mode = qm_o;
else if ( current_line == "w" )
query_mode = qm_w;
else if ( current_line == "nc" )
query_mode = qm_nc;
else if ( current_line == "nd" )
query_mode = qm_nd;
else if ( current_line == "ni" )
query_mode = qm_ni;
else if ( current_line == "no" )
query_mode = qm_no;
else if ( current_line == "nw" )
query_mode = qm_nw;
else if ( current_line == "all" )
query_mode = qm_all;
else if ( current_line == "ri" )
query_mode = qm_ri;
else if ( current_line == "pi" )
query_mode = qm_pi;
else if ( current_line == "mpi" )
query_mode = qm_mpi;
else if ( current_line == "si" )
query_mode = qm_si;
else if ( current_line == "lsi" )
query_mode = qm_lsi;
else if ( current_line == "path" )
query_mode = qm_path;
search();
glutPostRedisplay();
}
current_line.clear();
std::cout << '\n';
}
else
{
current_line += key;
std::cout << key;
}
}
// main function
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_SINGLE | GLUT_RGBA);
glutInitWindowPosition(100,100);
glutInitWindowSize(600, 600);
glutCreateWindow("boost::geometry::index::rtree GLUT test");
glutDisplayFunc(render_scene);
glutReshapeFunc(resize);
glutMouseFunc(mouse);
glutKeyboardFunc(keyboard);
glutMainLoop();
return 0;
}