graph_displayer_canvas.cc
author hegyi
Thu, 29 Mar 2007 12:17:36 +0000
changeset 199 128195bbab73
parent 190 2cac5b936a2b
child 201 879e47e5b731
permissions -rwxr-xr-x
Bugfix
     1 /* -*- C++ -*-
     2  *
     3  * This file is a part of LEMON, a generic C++ optimization library
     4  *
     5  * Copyright (C) 2003-2006
     6  * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
     7  * (Egervary Research Group on Combinatorial Optimization, EGRES).
     8  *
     9  * Permission to use, modify and distribute this software is granted
    10  * provided that this copyright notice appears in all copies. For
    11  * precise terms see the accompanying LICENSE file.
    12  *
    13  * This software is provided "AS IS" with no warranty of any kind,
    14  * express or implied, and with no claim as to its suitability for any
    15  * purpose.
    16  *
    17  */
    18 
    19 #include <mapstorage.h>
    20 #include <nbtab.h>
    21 #include <graph_displayer_canvas.h>
    22 #include <lemon/random.h>
    23 #include <cmath>
    24 
    25 GraphDisplayerCanvas::GraphDisplayerCanvas(NoteBookTab & mainw) :
    26   nodesmap(mainw.mapstorage->graph), edgesmap(mainw.mapstorage->graph), edgetextmap(mainw.mapstorage->graph),
    27   nodetextmap(mainw.mapstorage->graph), displayed_graph(*(root()), 0, 0),
    28   isbutton(0), active_item(NULL), target_item(NULL), nodemap_to_edit(""),
    29   edgemap_to_edit(""), autoscale(true), zoomtrack(false), radius_size(20), edge_width(10),
    30   was_redesigned(false), is_drawn(false), mytab(mainw),
    31   background_set(false)
    32 {
    33   //add mouse scroll event handler - it won't be changed, it handles zoom
    34   signal_event().connect(sigc::mem_fun(*this, &GraphDisplayerCanvas::scrollEventHandler), false);
    35 
    36   //base event handler is move tool
    37   actual_handler=signal_event().connect(sigc::mem_fun(*this, &GraphDisplayerCanvas::moveEventHandler), false);
    38   actual_tool=MOVE;
    39 
    40 
    41   active_node=INVALID;
    42   active_edge=INVALID;
    43   forming_edge=INVALID;
    44 
    45   setBackground();
    46 }
    47 
    48 void GraphDisplayerCanvas::setBackground()
    49 {
    50   if (background_set)
    51   {
    52     delete background;
    53   }
    54   if (mytab.mapstorage->isBackgroundSet())
    55   {
    56     background_set = true;
    57     refBackground = Gdk::Pixbuf::create_from_file(
    58       mytab.mapstorage->getBackgroundFilename());
    59     background = new Gnome::Canvas::Pixbuf(
    60         *(root()),
    61         0.0 - refBackground->get_width() / 2.0,
    62         0.0 - refBackground->get_height() / 2.0,
    63         refBackground);
    64     background->lower_to_bottom();
    65   }
    66   else
    67   {
    68     background_set = false;
    69   }
    70 }
    71 
    72 GraphDisplayerCanvas::~GraphDisplayerCanvas()
    73 {
    74   for (NodeIt n((mytab.mapstorage)->graph); n != INVALID; ++n)
    75     {
    76       delete nodesmap[n];
    77       delete nodetextmap[n];
    78     }
    79   
    80   for (EdgeIt e((mytab.mapstorage)->graph); e != INVALID; ++e)
    81     {
    82       delete edgesmap[e];
    83       delete edgetextmap[e];
    84     }
    85 }
    86 
    87 void GraphDisplayerCanvas::propertyChange(bool itisedge, int prop)
    88 {
    89   if(itisedge)
    90     {
    91       propertyUpdate(Edge(INVALID), prop);
    92     }
    93   else
    94     {
    95       propertyUpdate(Node(INVALID), prop);
    96     }
    97 }
    98 
    99 void GraphDisplayerCanvas::propertyUpdate(Edge edge)
   100 {
   101   for(int i=0;i<EDGE_PROPERTY_NUM;i++)
   102     {
   103       propertyUpdate(edge, i);
   104     }
   105 }
   106 
   107 void GraphDisplayerCanvas::propertyUpdate(Node node)
   108 {
   109   for(int i=0;i<NODE_PROPERTY_NUM;i++)
   110     {
   111       propertyUpdate(node, i);
   112     }
   113 }
   114 
   115 void GraphDisplayerCanvas::propertyUpdate(Node node, int prop)
   116 {
   117   std::string mapname=mytab.getActiveNodeMap(prop);
   118 
   119   if(is_drawn)
   120     {
   121       if(mapname!="")
   122 	{
   123 	  if( ( ((mytab.mapstorage)->nodemap_storage).find(mapname) != ((mytab.mapstorage)->nodemap_storage).end() ) )
   124 	    {
   125 	      switch(prop)
   126 		{
   127 		case N_RADIUS:
   128 		  changeNodeRadius(mapname, node);
   129 		  break;
   130 		case N_COLOR:
   131 		  changeNodeColor(mapname, node);
   132 		  break;
   133 		case N_TEXT:
   134 		  changeNodeText(mapname, node);
   135 		  break;
   136 		default:
   137 		  std::cerr<<"Error\n";
   138 		}
   139 	    }
   140 	}
   141       else //mapname==""
   142 	{
   143 	  Node node=INVALID;	
   144 	  switch(prop)
   145 	    {
   146 	    case N_RADIUS:
   147 	      resetNodeRadius(node);
   148 	      break;
   149 	    case N_COLOR:
   150 	      resetNodeColor(node);
   151 	      break;
   152 	    case N_TEXT:
   153 	      resetNodeText(node);
   154 	      break;
   155 	    default:
   156 	      std::cerr<<"Error\n";
   157 	    }
   158 	}
   159     }
   160 }
   161 
   162 void GraphDisplayerCanvas::propertyUpdate(Edge edge, int prop)
   163 {
   164   std::string mapname=mytab.getActiveEdgeMap(prop);
   165 
   166   if(is_drawn)
   167     {
   168       if(mapname!="")
   169 	{
   170 	  if( ( ((mytab.mapstorage)->edgemap_storage).find(mapname) != ((mytab.mapstorage)->edgemap_storage).end() ) )
   171 	    {
   172 	      switch(prop)
   173 		{
   174 		case E_WIDTH:
   175 		  changeEdgeWidth(mapname, edge);
   176 		  break;
   177 		case E_COLOR:
   178 		  changeEdgeColor(mapname, edge);
   179 		  break;
   180 		case E_TEXT:
   181 		  changeEdgeText(mapname, edge);
   182 		  break;
   183 		default:
   184 		  std::cerr<<"Error\n";
   185 		}
   186 	    }
   187 	}
   188       else //mapname==""
   189 	{
   190 	  switch(prop)
   191 	    {
   192 	    case E_WIDTH:
   193 	      resetEdgeWidth(edge);
   194 	      break;
   195 	    case E_COLOR:
   196 	      resetEdgeColor(edge);
   197 	      break;
   198 	    case E_TEXT:
   199 	      resetEdgeText(edge);
   200 	      break;
   201 	    default:
   202 	      std::cerr<<"Error\n";
   203 	    }
   204 	}
   205     }
   206 }
   207 
   208 void GraphDisplayerCanvas::drawGraph()
   209 {
   210   //first edges are drawn, to hide joining with nodes later
   211 
   212   for (EdgeIt i((mytab.mapstorage)->graph); i!=INVALID; ++i)
   213   {
   214     if (mytab.mapstorage->graph.source(i) == mytab.mapstorage->graph.target(i))
   215     {
   216       edgesmap[i]=new LoopEdge(displayed_graph, i, *this);
   217     }
   218     else
   219     {
   220       edgesmap[i]=new BrokenEdge(displayed_graph, i, *this);
   221     }
   222     //initializing edge-text as well, to empty string
   223 
   224     XY text_pos=mytab.mapstorage->arrow_pos[i];
   225     text_pos+=(XY(10,10));
   226 
   227     edgetextmap[i]=new Gnome::Canvas::Text(displayed_graph, text_pos.x, text_pos.y, "");
   228     edgetextmap[i]->property_fill_color().set_value("darkgreen");
   229     edgetextmap[i]->signal_event().connect(sigc::mem_fun(*this, &GraphDisplayerCanvas::mapEditEventHandler), false);
   230     edgetextmap[i]->raise_to_top();
   231   }
   232 
   233   //afterwards nodes come to be drawn
   234 
   235   for (NodeIt i((mytab.mapstorage)->graph); i!=INVALID; ++i)
   236   {
   237     //drawing bule nodes, with black line around them
   238 
   239     nodesmap[i]=new Gnome::Canvas::Ellipse(
   240         displayed_graph,
   241         (mytab.mapstorage)->coords[i].x-20,
   242         (mytab.mapstorage)->coords[i].y-20,
   243         (mytab.mapstorage)->coords[i].x+20,
   244         (mytab.mapstorage)->coords[i].y+20);
   245     *(nodesmap[i]) << Gnome::Canvas::Properties::fill_color("blue");
   246     *(nodesmap[i]) << Gnome::Canvas::Properties::outline_color("black");
   247     nodesmap[i]->raise_to_top();
   248 
   249     //initializing edge-text as well, to empty string
   250 
   251     XY text_pos(
   252         ((mytab.mapstorage)->coords[i].x+node_property_defaults[N_RADIUS]+5),
   253         ((mytab.mapstorage)->coords[i].y+node_property_defaults[N_RADIUS]+5));
   254 
   255     nodetextmap[i]=new Gnome::Canvas::Text(displayed_graph,
   256         text_pos.x, text_pos.y, "");
   257     nodetextmap[i]->property_fill_color().set_value("darkblue");
   258     nodetextmap[i]->signal_event().connect(sigc::mem_fun(*this, &GraphDisplayerCanvas::mapEditEventHandler), false);
   259     nodetextmap[i]->raise_to_top();
   260   }
   261 
   262   is_drawn=true;
   263 
   264   //upon drawing graph
   265   //properties have to
   266   //be set in as well
   267   for(int i=0;i<NODE_PROPERTY_NUM;i++)
   268     {
   269       propertyUpdate(Node(INVALID), i);
   270     }
   271 
   272   for(int i=0;i<EDGE_PROPERTY_NUM;i++)
   273     {
   274       propertyUpdate(Edge(INVALID), i);
   275     }
   276 
   277   updateScrollRegion();
   278 }
   279 
   280 void GraphDisplayerCanvas::clear()
   281 {
   282   active_node=INVALID;
   283   active_edge=INVALID;
   284   forming_edge=INVALID;
   285 
   286   for (NodeIt n((mytab.mapstorage)->graph); n != INVALID; ++n)
   287   {
   288     delete nodesmap[n];
   289     delete nodetextmap[n];
   290   }
   291 
   292   for (EdgeIt e((mytab.mapstorage)->graph); e != INVALID; ++e)
   293   {
   294     delete edgesmap[e];
   295     delete edgetextmap[e];
   296   }
   297 
   298   is_drawn=false;
   299 }
   300 
   301 void GraphDisplayerCanvas::setView(bool autoscale_p, bool zoomtrack_p, double width_p, double radius_p)
   302 {
   303   autoscale=autoscale_p;
   304   edge_width=width_p;
   305   radius_size=radius_p;
   306 
   307   if((!zoomtrack) && zoomtrack_p)
   308     {
   309       fixed_zoom_factor=get_pixels_per_unit();
   310     }
   311 
   312   zoomtrack=zoomtrack_p;
   313 
   314   propertyChange(false, N_RADIUS);
   315   propertyChange(true, E_WIDTH);
   316 }
   317 
   318 void GraphDisplayerCanvas::getView(bool & autoscale_p, bool & zoomtrack_p, double& width_p, double& radius_p)
   319 {
   320   autoscale_p=autoscale;
   321   zoomtrack_p=zoomtrack;
   322   width_p=edge_width;
   323   radius_p=radius_size;
   324 }
   325 
   326 void GraphDisplayerCanvas::reDesignGraph()
   327 {
   328   NodeIt firstnode((mytab.mapstorage)->graph);
   329   //is it not an empty graph?
   330   if(firstnode!=INVALID)
   331     {
   332       double max_coord=50000;
   333       double min_dist=20;
   334       double init_vector_length=25;
   335 
   336       if(!was_redesigned)
   337 	{
   338 	  NodeIt i((mytab.mapstorage)->graph);
   339 
   340 	  dim2::Point<double> init(init_vector_length*rnd(),
   341 				   init_vector_length*rnd());
   342 	  moveNode(init.x, init.y, nodesmap[i], i);
   343 	  was_redesigned=true;
   344 	}
   345 
   346       double attraction;
   347       double propulsation;
   348       int iterations;
   349 
   350       (mytab.mapstorage)->get_design_data(attraction, propulsation, iterations);
   351 
   352       //iteration counter
   353       for(int l=0;l<iterations;l++)
   354 	{
   355 	  Graph::NodeMap<double> x(mytab.mapstorage->graph);
   356 	  Graph::NodeMap<double> y(mytab.mapstorage->graph);
   357 	  XYMap<Graph::NodeMap<double> > actual_forces;
   358 	  actual_forces.setXMap(x);
   359 	  actual_forces.setYMap(y);
   360 
   361 	  //count actual force for each nodes
   362 	  for (NodeIt i((mytab.mapstorage)->graph); i!=INVALID; ++i)
   363 	    {
   364 	      //propulsation of nodes
   365 	      for (NodeIt j((mytab.mapstorage)->graph); j!=INVALID; ++j)
   366 		{
   367 		  if(i!=j)
   368 		    {
   369 		      lemon::dim2::Point<double> delta =
   370 			((mytab.mapstorage)->coords[i]-
   371 			 (mytab.mapstorage)->coords[j]);
   372 
   373 		      const double length_sqr=std::max(delta.normSquare(),min_dist);
   374 
   375 		      //normalize vector
   376 		      delta/=sqrt(length_sqr);
   377 
   378 		      //calculating propulsation strength
   379 		      //greater distance menas smaller propulsation strength
   380 		      delta*=propulsation/length_sqr;
   381 		    
   382 		      actual_forces.set(i,(actual_forces[i]+delta));
   383 		    }
   384 		}
   385 	      //attraction of nodes, to which actual node is bound
   386 	      for(OutEdgeIt ei((mytab.mapstorage)->graph,i);ei!=INVALID;++ei)
   387 		{
   388 		  lemon::dim2::Point<double> delta =
   389 		    ((mytab.mapstorage)->coords[i]-
   390 		     (mytab.mapstorage)->coords[mytab.mapstorage->
   391 					       graph.target(ei)]);
   392 		
   393 		  //calculating attraction strength
   394 		  //greater distance means greater strength
   395 		  delta*=attraction;
   396 		
   397 		  actual_forces.set(i,actual_forces[i]-delta);
   398 		}
   399 	      for(InEdgeIt ei((mytab.mapstorage)->graph,i);ei!=INVALID;++ei)
   400 		{
   401 		  lemon::dim2::Point<double> delta =
   402 		    ((mytab.mapstorage)->coords[i]-
   403 		     (mytab.mapstorage)->coords[mytab.mapstorage->
   404 					       graph.source(ei)]);
   405 		
   406 		  //calculating attraction strength
   407 		  //greater distance means greater strength
   408 		  delta*=attraction;
   409 		
   410 		  actual_forces.set(i,actual_forces[i]-delta);
   411 		}
   412 	    }
   413 	  for (NodeIt i((mytab.mapstorage)->graph); i!=INVALID; ++i)
   414 	    {
   415 	      if(((mytab.mapstorage)->coords[i].x)+actual_forces[i].x>max_coord)
   416 		{
   417 		  actual_forces[i].x=max_coord-((mytab.mapstorage)->coords[i].x);
   418 		  std::cout << "Correction! " << (((mytab.mapstorage)->coords[i].x)+actual_forces[i].x) << std::endl;
   419 		}
   420 	      else if(((mytab.mapstorage)->coords[i].x)+actual_forces[i].x<(0-max_coord))
   421 		{
   422 		  actual_forces[i].x=0-max_coord-((mytab.mapstorage)->coords[i].x);
   423 		  std::cout << "Correction! " << (((mytab.mapstorage)->coords[i].x)+actual_forces[i].x) << std::endl;
   424 		}
   425 	      if(((mytab.mapstorage)->coords[i].y)+actual_forces[i].y>max_coord)
   426 		{
   427 		  actual_forces[i].y=max_coord-((mytab.mapstorage)->coords[i].y);
   428 		  std::cout << "Correction! " << (((mytab.mapstorage)->coords[i].y)+actual_forces[i].y) << std::endl;
   429 		}
   430 	      else if(((mytab.mapstorage)->coords[i].y)+actual_forces[i].y<(0-max_coord))
   431 		{
   432 		  actual_forces[i].y=0-max_coord-((mytab.mapstorage)->coords[i].y);
   433 		  std::cout << "Correction! " << (((mytab.mapstorage)->coords[i].y)+actual_forces[i].y) << std::endl;
   434 		}
   435 	      moveNode(actual_forces[i].x, actual_forces[i].y, nodesmap[i], i);
   436 	    }
   437 	}
   438     }
   439 }
   440