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