diff options
Diffstat (limited to 'src/toys/rtree-toy.cpp')
-rw-r--r-- | src/toys/rtree-toy.cpp | 573 |
1 files changed, 573 insertions, 0 deletions
diff --git a/src/toys/rtree-toy.cpp b/src/toys/rtree-toy.cpp new file mode 100644 index 0000000..b7872fa --- /dev/null +++ b/src/toys/rtree-toy.cpp @@ -0,0 +1,573 @@ +/* + * Copyright 2009 Evangelos Katsikaros <vkatsikaros at yahoo dot gr> + * + * 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 <toys/path-cairo.h> +#include <toys/toy-framework-2.h> + +#include <time.h> +#include <vector> +#include <sstream> +#include <getopt.h> + +#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<colour> 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; +*/ |