/* -*- C++ -*- * * This file is a part of LEMON, a generic C++ optimization library * * Copyright (C) 2003-2006 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Research Group on Combinatorial Optimization, EGRES). * * Permission to use, modify and distribute this software is granted * provided that this copyright notice appears in all copies. For * precise terms see the accompanying LICENSE file. * * This software is provided "AS IS" with no warranty of any kind, * express or implied, and with no claim as to its suitability for any * purpose. * */ #include #include #include #include #include DigraphDisplayerCanvas::DigraphDisplayerCanvas(NoteBookTab & mainw) : nodesmap(mainw.mapstorage->digraph), arcsmap(mainw.mapstorage->digraph), arctextmap(mainw.mapstorage->digraph), nodetextmap(mainw.mapstorage->digraph), displayed_graph(*(root()), 0, 0), isbutton(0), active_item(NULL), target_item(NULL), nodemap_to_edit(""), arcmap_to_edit(""), autoscale(true), zoomtrack(false), radius_size(20), arc_width(10), was_redesigned(false), is_drawn(false), mytab(mainw), background_set(false) { //add mouse scroll event handler - it won't be changed, it handles zoom signal_event().connect(sigc::mem_fun(*this, &DigraphDisplayerCanvas::scrollEventHandler), false); //base event handler is move tool actual_handler=signal_event().connect(sigc::mem_fun(*this, &DigraphDisplayerCanvas::moveEventHandler), false); actual_tool=MOVE; active_node=INVALID; active_arc=INVALID; forming_arc=INVALID; setBackground(); } void DigraphDisplayerCanvas::setBackground() { if (background_set) { delete background; } if (mytab.mapstorage->isBackgroundSet()) { background_set = true; refBackground = Gdk::Pixbuf::create_from_file( mytab.mapstorage->getBackgroundFilename()); background = new Gnome::Canvas::Pixbuf( *(root()), 0.0 - refBackground->get_width() / 2.0, 0.0 - refBackground->get_height() / 2.0, refBackground); background->lower_to_bottom(); } else { background_set = false; } } DigraphDisplayerCanvas::~DigraphDisplayerCanvas() { for (NodeIt n((mytab.mapstorage)->digraph); n != INVALID; ++n) { delete nodesmap[n]; delete nodetextmap[n]; } for (ArcIt e((mytab.mapstorage)->digraph); e != INVALID; ++e) { delete arcsmap[e]; delete arctextmap[e]; } } void DigraphDisplayerCanvas::propertyChange(bool itisarc, int prop) { if(itisarc) { propertyUpdate(Arc(INVALID), prop); } else { propertyUpdate(Node(INVALID), prop); } } void DigraphDisplayerCanvas::propertyUpdate(Arc arc) { for(int i=0;i nodemaps = mytab.mapstorage->getNodeMapList(); bool found = false; for (std::vector::const_iterator it = nodemaps.begin(); it != nodemaps.end(); ++it) { if (*it == mapname) { found = true; break; } } if (found) { switch(prop) { case N_RADIUS: changeNodeRadius(mapname, node); break; case N_COLOR: changeNodeColor(mapname, node); break; case N_TEXT: changeNodeText(mapname, node); break; default: std::cerr<<"Error\n"; } } } else //mapname=="" { Node node=INVALID; switch(prop) { case N_RADIUS: resetNodeRadius(node); break; case N_COLOR: resetNodeColor(node); break; case N_TEXT: resetNodeText(node); break; default: std::cerr<<"Error\n"; } } } } void DigraphDisplayerCanvas::propertyUpdate(Arc arc, int prop) { std::string mapname=mytab.getActiveArcMap(prop); if(is_drawn) { if(mapname!="") { std::vector arcmaps = mytab.mapstorage->getArcMapList(); bool found = false; for (std::vector::const_iterator it = arcmaps.begin(); it != arcmaps.end(); ++it) { if (*it == mapname) { found = true; break; } } if (found) { switch(prop) { case E_WIDTH: changeArcWidth(mapname, arc); break; case E_COLOR: changeArcColor(mapname, arc); break; case E_TEXT: changeArcText(mapname, arc); break; default: std::cerr<<"Error\n"; } } } else //mapname=="" { switch(prop) { case E_WIDTH: resetArcWidth(arc); break; case E_COLOR: resetArcColor(arc); break; case E_TEXT: resetArcText(arc); break; default: std::cerr<<"Error\n"; } } } } void DigraphDisplayerCanvas::drawDigraph() { //first arcs are drawn, to hide joining with nodes later for (ArcIt i((mytab.mapstorage)->digraph); i!=INVALID; ++i) { if (mytab.mapstorage->digraph.source(i) == mytab.mapstorage->digraph.target(i)) { arcsmap[i]=new LoopArc(displayed_graph, i, *this); } else { arcsmap[i]=new BrokenArc(displayed_graph, i, *this); } //initializing arc-text as well, to empty string XY text_pos=mytab.mapstorage->getArrowCoords(i); text_pos+=(XY(10,10)); arctextmap[i]=new Gnome::Canvas::Text(displayed_graph, text_pos.x, text_pos.y, ""); arctextmap[i]->property_fill_color().set_value("darkgreen"); arctextmap[i]->signal_event().connect(sigc::mem_fun(*this, &DigraphDisplayerCanvas::mapEditEventHandler), false); arctextmap[i]->raise_to_top(); } //afterwards nodes come to be drawn for (NodeIt i((mytab.mapstorage)->digraph); i!=INVALID; ++i) { //drawing bule nodes, with black line around them nodesmap[i]=new Gnome::Canvas::Ellipse( displayed_graph, mytab.mapstorage->getNodeCoords(i).x-20, mytab.mapstorage->getNodeCoords(i).y-20, mytab.mapstorage->getNodeCoords(i).x+20, mytab.mapstorage->getNodeCoords(i).y+20); *(nodesmap[i]) << Gnome::Canvas::Properties::fill_color("blue"); *(nodesmap[i]) << Gnome::Canvas::Properties::outline_color("black"); nodesmap[i]->raise_to_top(); //initializing arc-text as well, to empty string XY text_pos( (mytab.mapstorage->getNodeCoords(i).x+node_property_defaults[N_RADIUS]+5), (mytab.mapstorage->getNodeCoords(i).y+node_property_defaults[N_RADIUS]+5)); nodetextmap[i]=new Gnome::Canvas::Text(displayed_graph, text_pos.x, text_pos.y, ""); nodetextmap[i]->property_fill_color().set_value("darkblue"); nodetextmap[i]->signal_event().connect(sigc::mem_fun(*this, &DigraphDisplayerCanvas::mapEditEventHandler), false); nodetextmap[i]->raise_to_top(); } is_drawn=true; //upon drawing digraph //properties have to //be set in as well for(int i=0;idigraph); n != INVALID; ++n) { delete nodesmap[n]; delete nodetextmap[n]; } for (ArcIt e((mytab.mapstorage)->digraph); e != INVALID; ++e) { delete arcsmap[e]; delete arctextmap[e]; } is_drawn=false; } void DigraphDisplayerCanvas::setView(bool autoscale_p, bool zoomtrack_p, double width_p, double radius_p) { autoscale=autoscale_p; arc_width=width_p; radius_size=radius_p; if((!zoomtrack) && zoomtrack_p) { fixed_zoom_factor=get_pixels_per_unit(); } zoomtrack=zoomtrack_p; propertyChange(false, N_RADIUS); propertyChange(true, E_WIDTH); } void DigraphDisplayerCanvas::getView(bool & autoscale_p, bool & zoomtrack_p, double& width_p, double& radius_p) { autoscale_p=autoscale; zoomtrack_p=zoomtrack; width_p=arc_width; radius_p=radius_size; } void DigraphDisplayerCanvas::reDesignDigraph() { MapStorage& ms = *mytab.mapstorage; NodeIt firstnode(ms.digraph); //is it not an empty digraph? if(firstnode!=INVALID) { double max_coord=50000; double min_dist=20; double init_vector_length=25; if(!was_redesigned) { NodeIt i(ms.digraph); dim2::Point init(init_vector_length*rnd(), init_vector_length*rnd()); moveNode(init.x, init.y, nodesmap[i], i); was_redesigned=true; } double attraction; double propulsation; int iterations; ms.get_design_data(attraction, propulsation, iterations); //iteration counter for(int l=0;l x(ms.digraph); Digraph::NodeMap y(ms.digraph); XYMap > actual_forces; actual_forces.setXMap(x); actual_forces.setYMap(y); //count actual force for each nodes for (NodeIt i(ms.digraph); i!=INVALID; ++i) { //propulsation of nodes for (NodeIt j(ms.digraph); j!=INVALID; ++j) { if(i!=j) { lemon::dim2::Point delta = (ms.getNodeCoords(i)- ms.getNodeCoords(j)); const double length_sqr=std::max(delta.normSquare(),min_dist); //normalize vector delta/=sqrt(length_sqr); //calculating propulsation strength //greater distance menas smaller propulsation strength delta*=propulsation/length_sqr; actual_forces.set(i,(actual_forces[i]+delta)); } } //attraction of nodes, to which actual node is bound for(OutArcIt ei(ms.digraph,i);ei!=INVALID;++ei) { lemon::dim2::Point delta = (ms.getNodeCoords(i)- ms.getNodeCoords(ms.digraph.target(ei))); //calculating attraction strength //greater distance means greater strength delta*=attraction; actual_forces.set(i,actual_forces[i]-delta); } for(InArcIt ei(ms.digraph,i);ei!=INVALID;++ei) { lemon::dim2::Point delta = (ms.getNodeCoords(i)- ms.getNodeCoords(ms.digraph.source(ei))); //calculating attraction strength //greater distance means greater strength delta*=attraction; actual_forces.set(i,actual_forces[i]-delta); } } for (NodeIt i(ms.digraph); i!=INVALID; ++i) { if((ms.getNodeCoords(i).x)+actual_forces[i].x>max_coord) { actual_forces[i].x=max_coord-(ms.getNodeCoords(i).x); std::cout << "Correction! " << ((ms.getNodeCoords(i).x)+actual_forces[i].x) << std::endl; } else if((ms.getNodeCoords(i).x)+actual_forces[i].x<(0-max_coord)) { actual_forces[i].x=0-max_coord-(ms.getNodeCoords(i).x); std::cout << "Correction! " << ((ms.getNodeCoords(i).x)+actual_forces[i].x) << std::endl; } if((ms.getNodeCoords(i).y)+actual_forces[i].y>max_coord) { actual_forces[i].y=max_coord-(ms.getNodeCoords(i).y); std::cout << "Correction! " << ((ms.getNodeCoords(i).y)+actual_forces[i].y) << std::endl; } else if((ms.getNodeCoords(i).y)+actual_forces[i].y<(0-max_coord)) { actual_forces[i].y=0-max_coord-(ms.getNodeCoords(i).y); std::cout << "Correction! " << ((ms.getNodeCoords(i).y)+actual_forces[i].y) << std::endl; } moveNode(actual_forces[i].x, actual_forces[i].y, nodesmap[i], i); } } } }