/* * Copyright 2009 Evangelos Katsikaros * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * (the "LGPL") or, at your option, under the terms of the Mozilla * Public License Version 1.1 (the "MPL"). If you do not alter this * notice, a recipient may use your version of this file under either * the MPL or the LGPL. * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY * OF ANY KIND, either express or implied. See the LGPL or the MPL for * the specific language governing rights and limitations. */ /* initial toy for redblack trees */ #include #include #include #include #include #include #include <2geom/orphan-code/rtree.h> #include "../2geom/orphan-code/rtree.cpp" //using std::vector; using namespace Geom; using namespace std; // make sure that in RTreeToy() constructor you assign the same number of colors // otherwise, they extra will be black :P const int no_of_colors = 8; const string search_str = "Mode: Search (Area: Click whitespace and Drag)"; const string update_str = "Mode: Update (Click Bounding Box (dark gray) and Drag) NOT implemented"; const string insert_str = "Mode: Insert (Click whitespace and Drag)" ; const string erase_str = "Mode: Delete (Click on Bounding Box (dark gray))"; const string help_str = "'I': Insert, 'U': Update, 'S': Search, 'D': Delete"; const char* program_name; class RTreeToy: public Toy { // PointSetHandle handle_set; // std::vector< Handle > rectangle_handles; std::vector< RectHandle > rectangles; Geom::Point starting_point; // during click and drag: start point of click Geom::Point ending_point; // during click and drag: end point of click (release) Geom::Point highlight_point; // not used // colors we are going to use for different purposes colour color_shape, color_shape_guide; colour color_select_area, color_select_area_guide; // red(a=0.6), red bool add_new_rect; bool delete_rect; Rect rect_chosen; // the rectangle of the search area Rect dummy_draw; // the "helper" rectangle that is shown during the click and drag (before the mouse release) // save the bounding boxes of the tree in here std::vector< std::vector< Rect > > rects_level; std::vector color_rtree_level; unsigned drawBB_color; bool drawBB_color_all; enum the_modes { INSERT_MODE = 0, UPDATE_MODE, DELETE_MODE, SEARCH_MODE, } mode; // insert/alter, search, delete modes bool drawBB; // draw bounding boxes of RTree string out_str, drawBB_str, drawBB_color_str; // printing of the tree //int help_counter; // the "x" of the label of each node static const int label_size = 15 ; // size the label of each node Geom::RTree rtree; void * hit; unsigned rect_id; // used for the keys that switch between modes enum menu_item_t { INSERT_I = 0, UPDATE_U, DELETE_D, SEARCH_S, BB_TOGGLE_T, BB_DRAW_0, BB_DRAW_1, BB_DRAW_2, BB_DRAW_3, BB_DRAW_4, BB_DRAW_5, BB_DRAW_ALL_O, TOTAL_ITEMS // this one must be the last item }; static const char* menu_items[TOTAL_ITEMS]; static const char keys[TOTAL_ITEMS]; void draw( cairo_t *cr, std::ostringstream *notify, int width, int height, bool save, std::ostringstream *timer_stream ) override { cairo_set_line_width( cr, 1 ); cairo_set_source_rgba( cr, color_shape ); cairo_stroke( cr ); // draw the shapes we save in the rtree for(auto & rectangle : rectangles){ rectangle.draw( cr, true ); } cairo_set_source_rgba( cr, color_shape ); cairo_stroke( cr ); // draw a rect if we did click & drag (so that we know what we are going to create) if( add_new_rect ){ dummy_draw = Rect( starting_point, ending_point ); cairo_rectangle( cr, dummy_draw ); if( mode == INSERT_MODE ){ cairo_set_source_rgba( cr, color_shape_guide ); } else if( mode == SEARCH_MODE ){ cairo_set_source_rgba( cr, color_select_area_guide ); } cairo_stroke( cr ); } // draw a rect for the search area cairo_rectangle( cr, rect_chosen ); cairo_set_source_rgba( cr, color_select_area ); cairo_stroke( cr ); *notify << help_str << "\n" << "'T': Bounding Boxes: " << drawBB_str << ", '0'-'" << no_of_colors << "', 'P': Show Layer: " << drawBB_color_str << "\n" << out_str; if( drawBB ){ for(unsigned color = 0 ; color < rects_level.size() ; color++ ){ if( drawBB_color == color || drawBB_color_all ){ for(auto & j : rects_level){ cairo_rectangle( cr, j ); } cairo_set_source_rgba( cr, color_rtree_level[color] ); cairo_stroke( cr ); } } } Toy::draw( cr, notify, width, height, save,timer_stream ); } void mouse_moved( GdkEventMotion* e ) override{ if(add_new_rect && ( mode == INSERT_MODE || mode == SEARCH_MODE ) ) { Toy::mouse_moved( e ); ending_point = Point( e->x, e->y ); } } void mouse_pressed( GdkEventButton* e ) override { Toy::mouse_pressed( e ); if(e->button == 1){ // left mouse button if( mode == INSERT_MODE ){ starting_point = Point( e->x, e->y ); ending_point = starting_point; add_new_rect = true; } else if( mode == SEARCH_MODE ){ starting_point = Point( e->x, e->y ); ending_point = starting_point; add_new_rect = true; } else if( mode == DELETE_MODE ) { Geom::Point mouse(e->x, e->y); unsigned i = 0; for( i = 0; i < rectangles.size(); i++) { hit = rectangles[i].hit(mouse); if( hit ) { break; } } if( hit ){ // erase specific element stringstream shape_id( rectangles[i].name ); unsigned shape_id_int; shape_id >> shape_id_int; rtree.erase( rectangles[i].pos, shape_id_int ); rectangles.erase( rectangles.begin() + i ); // check_if_deleted( ); // check_if_duplicates( ); delete_rect = true; } hit = NULL; } } else if( e->button == 2 ){ //middle button } else if( e->button == 3 ){ //right button } } void mouse_released( GdkEventButton* e ) override { Toy::mouse_released( e ); if( e->button == 1 ) { //left mouse button if( mode == INSERT_MODE ) { if( add_new_rect ){ ending_point = Point( e->x, e->y ); RectHandle t( Rect(starting_point, ending_point), false ); std::stringstream out; out << rect_id;; t.name = out.str(); rectangles.push_back( t ); rect_id++; insert_in_tree_the_last_rect(); find_rtree_subtrees_bounding_boxes( rtree ); add_new_rect = false; } } else if( mode == SEARCH_MODE ){ if( add_new_rect ){ ending_point = Point( e->x, e->y ); rect_chosen = Rect( starting_point, ending_point ); std::vector< int > result(0); if( rtree.root ){ rtree.search( rect_chosen, &result, rtree.root ); } std::cout << "Search results: " << result.size() << std::endl; for(int i : result){ std::cout << i << ", " ; } std::cout << std::endl; add_new_rect = false; } } else if( mode == DELETE_MODE ) { // mode: delete if( delete_rect ){ delete_rect = false; if( rtree.root ){ find_rtree_subtrees_bounding_boxes( rtree ); } std::cout << " \nTree:\n" << std::endl; rtree.print_tree( rtree.root, 0 ); std::cout << "...done\n" << std::endl; } } } else if( e->button == 2 ){ //middle button } else if( e->button == 3 ){ //right button } } void key_hit( GdkEventKey *e ) override { char choice = std::toupper( e->keyval ); switch ( choice ) { case 'I': mode = INSERT_MODE; out_str = insert_str; break; case 'S': mode = SEARCH_MODE; out_str = search_str; break; case 'D': mode = DELETE_MODE; out_str = erase_str; break; case 'U': mode = UPDATE_MODE; out_str = update_str; break; case 'T': if( drawBB ){ drawBB = false; drawBB_str = "OFF"; } else{ drawBB = true; drawBB_str = "ON"; } break; case 'P': drawBB_color_all = true; drawBB_color = 9; drawBB_color_str = "all"; break; case '0': drawBB_color_all = false; drawBB_color = 0; drawBB_color_str = "0"; break; case '1': drawBB_color_all = false; drawBB_color = 1; drawBB_color_str = "1"; break; case '2': drawBB_color_all = false; drawBB_color = 2; drawBB_color_str = "2"; break; case '3': drawBB_color_all = false; drawBB_color = 3; drawBB_color_str = "3"; break; case '4': drawBB_color_all = false; drawBB_color = 4; drawBB_color_str = "4"; break; case '5': drawBB_color_all = false; drawBB_color = 5; drawBB_color_str = "5"; break; case '6': drawBB_color_all = false; drawBB_color = 6; drawBB_color_str = "6"; break; case '7': drawBB_color_all = false; drawBB_color = 7; drawBB_color_str = "7"; break; } redraw(); } void insert_in_tree_the_last_rect(){ unsigned i = rectangles.size() - 1; Rect r1 = rectangles[i].pos; stringstream shape_id( rectangles[i].name ); unsigned shape_id_int; shape_id >> shape_id_int; // insert in R tree rtree.insert( r1, shape_id_int ); std::cout << " \nTree:\n" << std::endl; rtree.print_tree( rtree.root, 0 ); std::cout << "...done\n" << std::endl; }; void find_rtree_subtrees_bounding_boxes( Geom::RTree tree ){ if( tree.root ){ // clear existing bounding boxes for(auto & color : rects_level){ color.clear(); } save_bb( tree.root, 0); } }; // TODO fix this. void save_bb( Geom::RTreeNode* subtree_root, int depth ) { if( subtree_root->children_nodes.size() > 0 ){ // descend in each one of the elements and call print_tree for(auto & children_node : subtree_root->children_nodes){ Rect r1( children_node.bounding_box ); rects_level[ depth ].push_back( r1 ); if( depth == no_of_colors - 1 ){ // if we reached Nth levels of colors, roll back to color 0 save_bb( children_node.data, 0); } else{ save_bb( children_node.data, depth+1); } } } // else do nothing, entries are the rects themselves... }; public: RTreeToy(unsigned rmin, unsigned rmax, char /*handlefile*/): rectangles(0), color_shape(0, 0, 0, 0.9), color_shape_guide(1, 0, 0, 1), color_select_area(1, 0, 0, 0.6 ), color_select_area_guide(1, 0, 0, 1 ), //1, 0, 0, 1 add_new_rect( false ), delete_rect( false ), rect_chosen(), dummy_draw(), rects_level( no_of_colors ), color_rtree_level( no_of_colors, colour(0, 0, 0, 0) ), drawBB_color(9), drawBB_color_all(true), mode( INSERT_MODE ), drawBB(true), out_str( insert_str ), drawBB_str("ON"), drawBB_color_str("all"), rtree( rmin, rmax, QUADRATIC_SPIT ), hit( 0 ), rect_id( 0 ) { // only "bright" colors color_rtree_level[0] = colour(0, 0.80, 1, 1); // cyan color_rtree_level[1] = colour(0, 0.85, 0, 1); // green color_rtree_level[2] = colour(0.75, 0, 0.75, 1); // purple color_rtree_level[3] = colour(0, 0, 1, 1); // blue color_rtree_level[4] = colour(1, 0.62, 0, 1); // orange color_rtree_level[5] = colour(1, 0, 0.8, 1); // pink color_rtree_level[6] = colour(0.47, 0.26, 0.12, 1); color_rtree_level[7] = colour(1, 0.90, 0, 1); // yellow } }; int main(int argc, char **argv) { char* min_arg = NULL; char* max_arg = NULL; int set_min_max = 0; int c; while (1) { static struct option long_options[] = { /* These options set a flag. */ /* These options don't set a flag. We distinguish them by their indices. */ {"min-nodes", required_argument, 0, 'n'}, {"max-nodes", required_argument, 0, 'm'}, {"help", no_argument, 0, 'h'}, {0, 0, 0, 0} }; /* getopt_long stores the option index here. */ int option_index = 0; c = getopt_long (argc, argv, "n:m:h", long_options, &option_index); /* Detect the end of the options. */ if (c == -1){ break; } switch (c) { case 'n': min_arg = optarg; set_min_max += 1; break; case 'm': max_arg = optarg; set_min_max += 2; break; case 'h': std::cerr << "Usage: " << argv[0] << " options\n" << std::endl ; std::cerr << " -n --min-nodes=NUMBER minimum number in node.\n" << " -m --max-nodes=NUMBER maximum number in node.\n" << " -h --help Print this help.\n" << std::endl; exit(1); break; case '?': /* getopt_long already printed an error message. */ break; default: abort (); } } unsigned rmin = 0; unsigned rmax = 0; if( set_min_max == 3 ){ stringstream s1( min_arg ); s1 >> rmin; stringstream s2( max_arg ); s2 >> rmax; if( rmax <= rmin || rmax < 2 || rmin < 1 ){ std::cerr << "Rtree set to 2, 3" << std::endl ; rmin = 2; rmax = 3; } } else{ std::cerr << "Rtree set to 2, 3 ." << std::endl ; rmin = 2; rmax = 3; } char handlefile = 'T'; std::cout << "rmin: " << rmin << " rmax:" << rmax << std::endl; init(argc, argv, new RTreeToy( rmin, rmax, handlefile) ); return 0; } const char* RTreeToy::menu_items[] = { "Insert / Alter Rectangle", "Search Rectangle", "Delete Reactangle", "Toggle" }; const char RTreeToy::keys[] = { 'I', 'U', 'S', 'D', 'T', '0', '1', '2', '3', '4', '5', 'P' }; /* intersection test Rect r1( Point(100, 100), Point(150, 150)), r2( Point(200, 200), Point(250, 250)), r3( Point(50, 50), Point(100, 100)); OptRect a_intersection_b; a_intersection_b = intersect( r1, r2 ); std::cout << "r1, r2 " << a_intersection_b.empty() << std::endl; a_intersection_b = intersect( r1, r3 ); std::cout << "r1, r3 " << a_intersection_b.empty() << std::endl; */