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