graph_displayer_canvas.cc
author hegyi
Mon, 30 Oct 2006 15:43:13 +0000
changeset 178 a96d2a540454
parent 174 95872af46fc4
child 180 911c6ba0e3c8
permissions -rwxr-xr-x
If visualization is not autoscaled, edges with widths associated with negative map values will be hidden.
     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 "graph_displayer_canvas.h"
    20 #include <lemon/random.h>
    21 #include <cmath>
    22 
    23 GraphDisplayerCanvas::GraphDisplayerCanvas(NoteBookTab & mainw) :
    24   nodesmap(mainw.mapstorage.graph), edgesmap(mainw.mapstorage.graph), edgetextmap(mainw.mapstorage.graph),
    25   nodetextmap(mainw.mapstorage.graph), displayed_graph(*(root()), 0, 0),
    26   isbutton(0), active_item(NULL), target_item(NULL), nodemap_to_edit(""),
    27   edgemap_to_edit(""), autoscale(true), zoomtrack(false), radius_size(20), edge_width(10),
    28   was_redesigned(false), is_drawn(false), mytab(mainw)
    29 {
    30   //base event handler is move tool
    31   actual_handler=signal_event().connect(sigc::mem_fun(*this, &GraphDisplayerCanvas::moveEventHandler), false);
    32   actual_tool=MOVE;
    33 
    34   active_node=INVALID;
    35   active_edge=INVALID;
    36   forming_edge=INVALID;
    37 }
    38 
    39 GraphDisplayerCanvas::~GraphDisplayerCanvas()
    40 {
    41   for (NodeIt n((mytab.mapstorage).graph); n != INVALID; ++n)
    42     {
    43       delete nodesmap[n];
    44       delete nodetextmap[n];
    45     }
    46   
    47   for (EdgeIt e((mytab.mapstorage).graph); e != INVALID; ++e)
    48     {
    49       delete edgesmap[e];
    50       delete edgetextmap[e];
    51     }
    52 }
    53 
    54 void GraphDisplayerCanvas::propertyChange(bool itisedge, int prop)
    55 {
    56   if(itisedge)
    57     {
    58       propertyUpdate(Edge(INVALID), prop);
    59     }
    60   else
    61     {
    62       propertyUpdate(Node(INVALID), prop);
    63     }
    64 }
    65 
    66 void GraphDisplayerCanvas::propertyUpdate(Edge edge)
    67 {
    68   for(int i=0;i<EDGE_PROPERTY_NUM;i++)
    69     {
    70       propertyUpdate(edge, i);
    71     }
    72 }
    73 
    74 void GraphDisplayerCanvas::propertyUpdate(Node node)
    75 {
    76   for(int i=0;i<NODE_PROPERTY_NUM;i++)
    77     {
    78       propertyUpdate(node, i);
    79     }
    80 }
    81 
    82 void GraphDisplayerCanvas::propertyUpdate(Node node, int prop)
    83 {
    84   std::string mapname=mytab.getActiveNodeMap(prop);
    85 
    86   if(is_drawn)
    87     {
    88       if(mapname!="")
    89 	{
    90 	  if( ( ((mytab.mapstorage).nodemap_storage).find(mapname) != ((mytab.mapstorage).nodemap_storage).end() ) )
    91 	    {
    92 	      switch(prop)
    93 		{
    94 		case N_RADIUS:
    95 		  changeNodeRadius(mapname, node);
    96 		  break;
    97 		case N_COLOR:
    98 		  changeNodeColor(mapname, node);
    99 		  break;
   100 		case N_TEXT:
   101 		  changeNodeText(mapname, node);
   102 		  break;
   103 		default:
   104 		  std::cerr<<"Error\n";
   105 		}
   106 	    }
   107 	}
   108       else //mapname==""
   109 	{
   110 	  Node node=INVALID;	
   111 	  switch(prop)
   112 	    {
   113 	    case N_RADIUS:
   114 	      resetNodeRadius(node);
   115 	      break;
   116 	    case N_COLOR:
   117 	      resetNodeColor(node);
   118 	      break;
   119 	    case N_TEXT:
   120 	      resetNodeText(node);
   121 	      break;
   122 	    default:
   123 	      std::cerr<<"Error\n";
   124 	    }
   125 	}
   126     }
   127 }
   128 
   129 void GraphDisplayerCanvas::propertyUpdate(Edge edge, int prop)
   130 {
   131   std::string mapname=mytab.getActiveEdgeMap(prop);
   132 
   133   if(is_drawn)
   134     {
   135       if(mapname!="")
   136 	{
   137 	  if( ( ((mytab.mapstorage).edgemap_storage).find(mapname) != ((mytab.mapstorage).edgemap_storage).end() ) )
   138 	    {
   139 	      switch(prop)
   140 		{
   141 		case E_WIDTH:
   142 		  changeEdgeWidth(mapname, edge);
   143 		  break;
   144 		case E_COLOR:
   145 		  changeEdgeColor(mapname, edge);
   146 		  break;
   147 		case E_TEXT:
   148 		  changeEdgeText(mapname, edge);
   149 		  break;
   150 		default:
   151 		  std::cerr<<"Error\n";
   152 		}
   153 	    }
   154 	}
   155       else //mapname==""
   156 	{
   157 	  switch(prop)
   158 	    {
   159 	    case E_WIDTH:
   160 	      resetEdgeWidth(edge);
   161 	      break;
   162 	    case E_COLOR:
   163 	      resetEdgeColor(edge);
   164 	      break;
   165 	    case E_TEXT:
   166 	      resetEdgeText(edge);
   167 	      break;
   168 	    default:
   169 	      std::cerr<<"Error\n";
   170 	    }
   171 	}
   172     }
   173 }
   174 
   175 void GraphDisplayerCanvas::drawGraph()
   176 {
   177   //first edges are drawn, to hide joining with nodes later
   178 
   179   for (EdgeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
   180   {
   181     if (mytab.mapstorage.graph.source(i) == mytab.mapstorage.graph.target(i))
   182     {
   183       edgesmap[i]=new LoopEdge(displayed_graph, i, *this);
   184     }
   185     else
   186     {
   187       edgesmap[i]=new BrokenEdge(displayed_graph, i, *this);
   188     }
   189     //initializing edge-text as well, to empty string
   190 
   191     XY text_pos=mytab.mapstorage.arrow_pos[i];
   192     text_pos+=(XY(10,10));
   193 
   194     edgetextmap[i]=new Gnome::Canvas::Text(displayed_graph, text_pos.x, text_pos.y, "");
   195     edgetextmap[i]->property_fill_color().set_value("darkgreen");
   196     edgetextmap[i]->signal_event().connect(sigc::mem_fun(*this, &GraphDisplayerCanvas::mapEditEventHandler), false);
   197     edgetextmap[i]->raise_to_top();
   198   }
   199 
   200   //afterwards nodes come to be drawn
   201 
   202   for (NodeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
   203   {
   204     //drawing bule nodes, with black line around them
   205 
   206     nodesmap[i]=new Gnome::Canvas::Ellipse(
   207         displayed_graph,
   208         (mytab.mapstorage).coords[i].x-20,
   209         (mytab.mapstorage).coords[i].y-20,
   210         (mytab.mapstorage).coords[i].x+20,
   211         (mytab.mapstorage).coords[i].y+20);
   212     *(nodesmap[i]) << Gnome::Canvas::Properties::fill_color("blue");
   213     *(nodesmap[i]) << Gnome::Canvas::Properties::outline_color("black");
   214     nodesmap[i]->raise_to_top();
   215 
   216     //initializing edge-text as well, to empty string
   217 
   218     XY text_pos(
   219         ((mytab.mapstorage).coords[i].x+node_property_defaults[N_RADIUS]+5),
   220         ((mytab.mapstorage).coords[i].y+node_property_defaults[N_RADIUS]+5));
   221 
   222     nodetextmap[i]=new Gnome::Canvas::Text(displayed_graph,
   223         text_pos.x, text_pos.y, "");
   224     nodetextmap[i]->property_fill_color().set_value("darkblue");
   225     nodetextmap[i]->signal_event().connect(sigc::mem_fun(*this, &GraphDisplayerCanvas::mapEditEventHandler), false);
   226     nodetextmap[i]->raise_to_top();
   227   }
   228 
   229   is_drawn=true;
   230 
   231   //upon drawing graph
   232   //properties have to
   233   //be set in as well
   234   for(int i=0;i<NODE_PROPERTY_NUM;i++)
   235     {
   236       propertyUpdate(Node(INVALID), i);
   237     }
   238 
   239   for(int i=0;i<EDGE_PROPERTY_NUM;i++)
   240     {
   241       propertyUpdate(Edge(INVALID), i);
   242     }
   243 
   244   updateScrollRegion();
   245 }
   246 
   247 void GraphDisplayerCanvas::clear()
   248 {
   249   active_node=INVALID;
   250   active_edge=INVALID;
   251   forming_edge=INVALID;
   252 
   253   for (NodeIt n((mytab.mapstorage).graph); n != INVALID; ++n)
   254   {
   255     delete nodesmap[n];
   256     delete nodetextmap[n];
   257   }
   258 
   259   for (EdgeIt e((mytab.mapstorage).graph); e != INVALID; ++e)
   260   {
   261     delete edgesmap[e];
   262     delete edgetextmap[e];
   263   }
   264 
   265   is_drawn=false;
   266 }
   267 
   268 void GraphDisplayerCanvas::setView(bool autoscale_p, bool zoomtrack_p, double width_p, double radius_p)
   269 {
   270   autoscale=autoscale_p;
   271   edge_width=width_p;
   272   radius_size=radius_p;
   273 
   274   if((!zoomtrack) && zoomtrack_p)
   275     {
   276       fixed_zoom_factor=get_pixels_per_unit();
   277     }
   278 
   279   zoomtrack=zoomtrack_p;
   280 
   281   propertyChange(false, N_RADIUS);
   282   propertyChange(true, E_WIDTH);
   283 }
   284 
   285 void GraphDisplayerCanvas::getView(bool & autoscale_p, bool & zoomtrack_p, double& width_p, double& radius_p)
   286 {
   287   autoscale_p=autoscale;
   288   zoomtrack_p=zoomtrack;
   289   width_p=edge_width;
   290   radius_p=radius_size;
   291 }
   292 
   293 void GraphDisplayerCanvas::reDesignGraph()
   294 {
   295   double min_dist=20;
   296   double init_vector_length=25;
   297 
   298   if(!was_redesigned)
   299     {
   300       NodeIt i((mytab.mapstorage).graph);
   301 
   302       dim2::Point<double> init(init_vector_length*rnd(),
   303 			       init_vector_length*rnd());
   304       moveNode(init.x, init.y, nodesmap[i], i);
   305       was_redesigned=true;
   306     }
   307 
   308   double attraction;
   309   double propulsation;
   310   int iterations;
   311 
   312   (mytab.mapstorage).get_design_data(attraction, propulsation, iterations);
   313 
   314   //iteration counter
   315   for(int l=0;l<iterations;l++)
   316     {
   317       Graph::NodeMap<double> x(mytab.mapstorage.graph);
   318       Graph::NodeMap<double> y(mytab.mapstorage.graph);
   319       XYMap<Graph::NodeMap<double> > actual_forces;
   320       actual_forces.setXMap(x);
   321       actual_forces.setYMap(y);
   322 
   323       lemon::dim2::Point<double> delta;
   324 
   325       //count actual force for each nodes
   326       for (NodeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
   327 	{
   328 	  //propulsation of nodes
   329 	  for (NodeIt j((mytab.mapstorage).graph); j!=INVALID; ++j)
   330 	    {
   331 	      if(i!=j)
   332 		{
   333 		  delta=((mytab.mapstorage).coords[i]-(mytab.mapstorage).coords[j]);
   334 
   335 		  double length_sqr=delta.normSquare();
   336 		  double length=sqrt(length_sqr);
   337 		  if(length_sqr<min_dist)
   338 		    {
   339 		      length_sqr=min_dist;
   340 		    }
   341 
   342 		  //normalize vector
   343 		  delta/=length;
   344 
   345 		  //calculating propulsation strength
   346 		  //greater distance menas smaller propulsation strength
   347 		  delta*=propulsation/length_sqr;
   348 		    
   349 		  actual_forces.set(i,(actual_forces[i]+delta));
   350 		}
   351 	    }
   352 	  //attraction of nodes, to which actual node is bound
   353 	  for(OutEdgeIt ei((mytab.mapstorage).graph,i);ei!=INVALID;++ei)
   354 	    {
   355 	      delta=((mytab.mapstorage).coords[i]-(mytab.mapstorage).coords[mytab.mapstorage.graph.target(ei)]);
   356 
   357 	      double length_sqr=delta.normSquare();
   358 	      double length=sqrt(length_sqr);
   359 	      if(length_sqr<min_dist)
   360 		{
   361 		  length_sqr=min_dist;
   362 		}
   363 
   364 	      //normalize vector
   365 	      delta/=length;
   366 
   367 	      //calculating attraction strength
   368 	      //greater distance means greater strength
   369 	      delta*=attraction*length;
   370 
   371 	      actual_forces.set(i,actual_forces[i]-delta);
   372 	    }
   373 	  for(InEdgeIt ei((mytab.mapstorage).graph,i);ei!=INVALID;++ei)
   374 	    {
   375 	      delta=((mytab.mapstorage).coords[i]-(mytab.mapstorage).coords[mytab.mapstorage.graph.source(ei)]);
   376 
   377 	      double length_sqr=delta.normSquare();
   378 	      double length=sqrt(length_sqr);
   379 	      if(length_sqr<min_dist)
   380 		{
   381 		  length_sqr=min_dist;
   382 		}
   383 
   384 	      //normalize vector
   385 	      delta/=length;
   386 
   387 	      //calculating attraction strength
   388 	      //greater distance means greater strength
   389 	      delta*=attraction*length;
   390 
   391 	      actual_forces.set(i,actual_forces[i]-delta);
   392 	    }
   393 	}
   394       for (NodeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
   395 	{
   396 	  moveNode(actual_forces[i].x, actual_forces[i].y, nodesmap[i], i);
   397 	}
   398     }
   399 }
   400