graph_displayer_canvas.cc
changeset 1 67188bd752db
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/graph_displayer_canvas.cc	Mon Jul 07 08:10:39 2008 -0500
     1.3 @@ -0,0 +1,461 @@
     1.4 +/* -*- C++ -*-
     1.5 + *
     1.6 + * This file is a part of LEMON, a generic C++ optimization library
     1.7 + *
     1.8 + * Copyright (C) 2003-2006
     1.9 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
    1.10 + * (Egervary Research Group on Combinatorial Optimization, EGRES).
    1.11 + *
    1.12 + * Permission to use, modify and distribute this software is granted
    1.13 + * provided that this copyright notice appears in all copies. For
    1.14 + * precise terms see the accompanying LICENSE file.
    1.15 + *
    1.16 + * This software is provided "AS IS" with no warranty of any kind,
    1.17 + * express or implied, and with no claim as to its suitability for any
    1.18 + * purpose.
    1.19 + *
    1.20 + */
    1.21 +
    1.22 +#include <mapstorage.h>
    1.23 +#include <nbtab.h>
    1.24 +#include <graph_displayer_canvas.h>
    1.25 +#include <lemon/random.h>
    1.26 +#include <cmath>
    1.27 +
    1.28 +DigraphDisplayerCanvas::DigraphDisplayerCanvas(NoteBookTab & mainw) :
    1.29 +  nodesmap(mainw.mapstorage->digraph), arcsmap(mainw.mapstorage->digraph), arctextmap(mainw.mapstorage->digraph),
    1.30 +  nodetextmap(mainw.mapstorage->digraph), displayed_graph(*(root()), 0, 0),
    1.31 +  isbutton(0), active_item(NULL), target_item(NULL), nodemap_to_edit(""),
    1.32 +  arcmap_to_edit(""), autoscale(true), zoomtrack(false), radius_size(20), arc_width(10),
    1.33 +  was_redesigned(false), is_drawn(false), mytab(mainw),
    1.34 +  background_set(false)
    1.35 +{
    1.36 +  //add mouse scroll event handler - it won't be changed, it handles zoom
    1.37 +  signal_event().connect(sigc::mem_fun(*this, &DigraphDisplayerCanvas::scrollEventHandler), false);
    1.38 +
    1.39 +  //base event handler is move tool
    1.40 +  actual_handler=signal_event().connect(sigc::mem_fun(*this, &DigraphDisplayerCanvas::moveEventHandler), false);
    1.41 +  actual_tool=MOVE;
    1.42 +
    1.43 +
    1.44 +  active_node=INVALID;
    1.45 +  active_arc=INVALID;
    1.46 +  forming_arc=INVALID;
    1.47 +
    1.48 +  setBackground();
    1.49 +}
    1.50 +
    1.51 +void DigraphDisplayerCanvas::setBackground()
    1.52 +{
    1.53 +  if (background_set)
    1.54 +  {
    1.55 +    delete background;
    1.56 +  }
    1.57 +  if (mytab.mapstorage->isBackgroundSet())
    1.58 +  {
    1.59 +    background_set = true;
    1.60 +    refBackground = Gdk::Pixbuf::create_from_file(
    1.61 +      mytab.mapstorage->getBackgroundFilename());
    1.62 +    background = new Gnome::Canvas::Pixbuf(
    1.63 +        *(root()),
    1.64 +        0.0 - refBackground->get_width() / 2.0,
    1.65 +        0.0 - refBackground->get_height() / 2.0,
    1.66 +        refBackground);
    1.67 +    background->lower_to_bottom();
    1.68 +  }
    1.69 +  else
    1.70 +  {
    1.71 +    background_set = false;
    1.72 +  }
    1.73 +}
    1.74 +
    1.75 +DigraphDisplayerCanvas::~DigraphDisplayerCanvas()
    1.76 +{
    1.77 +  for (NodeIt n((mytab.mapstorage)->digraph); n != INVALID; ++n)
    1.78 +    {
    1.79 +      delete nodesmap[n];
    1.80 +      delete nodetextmap[n];
    1.81 +    }
    1.82 +  
    1.83 +  for (ArcIt e((mytab.mapstorage)->digraph); e != INVALID; ++e)
    1.84 +    {
    1.85 +      delete arcsmap[e];
    1.86 +      delete arctextmap[e];
    1.87 +    }
    1.88 +}
    1.89 +
    1.90 +void DigraphDisplayerCanvas::propertyChange(bool itisarc, int prop)
    1.91 +{
    1.92 +  if(itisarc)
    1.93 +    {
    1.94 +      propertyUpdate(Arc(INVALID), prop);
    1.95 +    }
    1.96 +  else
    1.97 +    {
    1.98 +      propertyUpdate(Node(INVALID), prop);
    1.99 +    }
   1.100 +}
   1.101 +
   1.102 +void DigraphDisplayerCanvas::propertyUpdate(Arc arc)
   1.103 +{
   1.104 +  for(int i=0;i<EDGE_PROPERTY_NUM;i++)
   1.105 +    {
   1.106 +      propertyUpdate(arc, i);
   1.107 +    }
   1.108 +}
   1.109 +
   1.110 +void DigraphDisplayerCanvas::propertyUpdate(Node node)
   1.111 +{
   1.112 +  for(int i=0;i<NODE_PROPERTY_NUM;i++)
   1.113 +    {
   1.114 +      propertyUpdate(node, i);
   1.115 +    }
   1.116 +}
   1.117 +
   1.118 +void DigraphDisplayerCanvas::propertyUpdate(Node node, int prop)
   1.119 +{
   1.120 +  std::string mapname=mytab.getActiveNodeMap(prop);
   1.121 +
   1.122 +  if(is_drawn)
   1.123 +  {
   1.124 +    if(mapname!="")
   1.125 +    {
   1.126 +      std::vector<std::string> nodemaps = mytab.mapstorage->getNodeMapList();
   1.127 +      bool found = false;
   1.128 +      for (std::vector<std::string>::const_iterator it = nodemaps.begin();
   1.129 +          it != nodemaps.end(); ++it)
   1.130 +      {
   1.131 +        if (*it == mapname)
   1.132 +        {
   1.133 +          found = true;
   1.134 +          break;
   1.135 +        }
   1.136 +      }
   1.137 +      if (found)
   1.138 +      {
   1.139 +        switch(prop)
   1.140 +        {
   1.141 +          case N_RADIUS:
   1.142 +            changeNodeRadius(mapname, node);
   1.143 +            break;
   1.144 +          case N_COLOR:
   1.145 +            changeNodeColor(mapname, node);
   1.146 +            break;
   1.147 +          case N_TEXT:
   1.148 +            changeNodeText(mapname, node);
   1.149 +            break;
   1.150 +          default:
   1.151 +            std::cerr<<"Error\n";
   1.152 +        }
   1.153 +      }
   1.154 +    }
   1.155 +    else //mapname==""
   1.156 +    {
   1.157 +      Node node=INVALID;
   1.158 +      switch(prop)
   1.159 +      {
   1.160 +        case N_RADIUS:
   1.161 +          resetNodeRadius(node);
   1.162 +          break;
   1.163 +        case N_COLOR:
   1.164 +          resetNodeColor(node);
   1.165 +          break;
   1.166 +        case N_TEXT:
   1.167 +          resetNodeText(node);
   1.168 +          break;
   1.169 +        default:
   1.170 +          std::cerr<<"Error\n";
   1.171 +      }
   1.172 +    }
   1.173 +  }
   1.174 +}
   1.175 +
   1.176 +void DigraphDisplayerCanvas::propertyUpdate(Arc arc, int prop)
   1.177 +{
   1.178 +  std::string mapname=mytab.getActiveArcMap(prop);
   1.179 +
   1.180 +  if(is_drawn)
   1.181 +  {
   1.182 +    if(mapname!="")
   1.183 +    {
   1.184 +      std::vector<std::string> arcmaps = mytab.mapstorage->getArcMapList();
   1.185 +      bool found = false;
   1.186 +      for (std::vector<std::string>::const_iterator it = arcmaps.begin();
   1.187 +          it != arcmaps.end(); ++it)
   1.188 +      {
   1.189 +        if (*it == mapname)
   1.190 +        {
   1.191 +          found = true;
   1.192 +          break;
   1.193 +        }
   1.194 +      }
   1.195 +      if (found)
   1.196 +      {
   1.197 +        switch(prop)
   1.198 +        {
   1.199 +          case E_WIDTH:
   1.200 +            changeArcWidth(mapname, arc);
   1.201 +            break;
   1.202 +          case E_COLOR:
   1.203 +            changeArcColor(mapname, arc);
   1.204 +            break;
   1.205 +          case E_TEXT:
   1.206 +            changeArcText(mapname, arc);
   1.207 +            break;
   1.208 +          default:
   1.209 +            std::cerr<<"Error\n";
   1.210 +        }
   1.211 +      }
   1.212 +    }
   1.213 +    else //mapname==""
   1.214 +    {
   1.215 +      switch(prop)
   1.216 +      {
   1.217 +        case E_WIDTH:
   1.218 +          resetArcWidth(arc);
   1.219 +          break;
   1.220 +        case E_COLOR:
   1.221 +          resetArcColor(arc);
   1.222 +          break;
   1.223 +        case E_TEXT:
   1.224 +          resetArcText(arc);
   1.225 +          break;
   1.226 +        default:
   1.227 +          std::cerr<<"Error\n";
   1.228 +      }
   1.229 +    }
   1.230 +  }
   1.231 +}
   1.232 +
   1.233 +void DigraphDisplayerCanvas::drawDigraph()
   1.234 +{
   1.235 +  //first arcs are drawn, to hide joining with nodes later
   1.236 +
   1.237 +  for (ArcIt i((mytab.mapstorage)->digraph); i!=INVALID; ++i)
   1.238 +  {
   1.239 +    if (mytab.mapstorage->digraph.source(i) == mytab.mapstorage->digraph.target(i))
   1.240 +    {
   1.241 +      arcsmap[i]=new LoopArc(displayed_graph, i, *this);
   1.242 +    }
   1.243 +    else
   1.244 +    {
   1.245 +      arcsmap[i]=new BrokenArc(displayed_graph, i, *this);
   1.246 +    }
   1.247 +    //initializing arc-text as well, to empty string
   1.248 +
   1.249 +    XY text_pos=mytab.mapstorage->getArrowCoords(i);
   1.250 +    text_pos+=(XY(10,10));
   1.251 +
   1.252 +    arctextmap[i]=new Gnome::Canvas::Text(displayed_graph, text_pos.x, text_pos.y, "");
   1.253 +    arctextmap[i]->property_fill_color().set_value("darkgreen");
   1.254 +    arctextmap[i]->signal_event().connect(sigc::mem_fun(*this, &DigraphDisplayerCanvas::mapEditEventHandler), false);
   1.255 +    arctextmap[i]->raise_to_top();
   1.256 +  }
   1.257 +
   1.258 +  //afterwards nodes come to be drawn
   1.259 +
   1.260 +  for (NodeIt i((mytab.mapstorage)->digraph); i!=INVALID; ++i)
   1.261 +  {
   1.262 +    //drawing bule nodes, with black line around them
   1.263 +
   1.264 +    nodesmap[i]=new Gnome::Canvas::Ellipse(
   1.265 +        displayed_graph,
   1.266 +        mytab.mapstorage->getNodeCoords(i).x-20,
   1.267 +        mytab.mapstorage->getNodeCoords(i).y-20,
   1.268 +        mytab.mapstorage->getNodeCoords(i).x+20,
   1.269 +        mytab.mapstorage->getNodeCoords(i).y+20);
   1.270 +    *(nodesmap[i]) << Gnome::Canvas::Properties::fill_color("blue");
   1.271 +    *(nodesmap[i]) << Gnome::Canvas::Properties::outline_color("black");
   1.272 +    nodesmap[i]->raise_to_top();
   1.273 +
   1.274 +    //initializing arc-text as well, to empty string
   1.275 +
   1.276 +    XY text_pos(
   1.277 +        (mytab.mapstorage->getNodeCoords(i).x+node_property_defaults[N_RADIUS]+5),
   1.278 +        (mytab.mapstorage->getNodeCoords(i).y+node_property_defaults[N_RADIUS]+5));
   1.279 +
   1.280 +    nodetextmap[i]=new Gnome::Canvas::Text(displayed_graph,
   1.281 +        text_pos.x, text_pos.y, "");
   1.282 +    nodetextmap[i]->property_fill_color().set_value("darkblue");
   1.283 +    nodetextmap[i]->signal_event().connect(sigc::mem_fun(*this, &DigraphDisplayerCanvas::mapEditEventHandler), false);
   1.284 +    nodetextmap[i]->raise_to_top();
   1.285 +  }
   1.286 +
   1.287 +  is_drawn=true;
   1.288 +
   1.289 +  //upon drawing digraph
   1.290 +  //properties have to
   1.291 +  //be set in as well
   1.292 +  for(int i=0;i<NODE_PROPERTY_NUM;i++)
   1.293 +    {
   1.294 +      propertyUpdate(Node(INVALID), i);
   1.295 +    }
   1.296 +
   1.297 +  for(int i=0;i<EDGE_PROPERTY_NUM;i++)
   1.298 +    {
   1.299 +      propertyUpdate(Arc(INVALID), i);
   1.300 +    }
   1.301 +
   1.302 +  updateScrollRegion();
   1.303 +}
   1.304 +
   1.305 +void DigraphDisplayerCanvas::clear()
   1.306 +{
   1.307 +  active_node=INVALID;
   1.308 +  active_arc=INVALID;
   1.309 +  forming_arc=INVALID;
   1.310 +
   1.311 +  for (NodeIt n((mytab.mapstorage)->digraph); n != INVALID; ++n)
   1.312 +  {
   1.313 +    delete nodesmap[n];
   1.314 +    delete nodetextmap[n];
   1.315 +  }
   1.316 +
   1.317 +  for (ArcIt e((mytab.mapstorage)->digraph); e != INVALID; ++e)
   1.318 +  {
   1.319 +    delete arcsmap[e];
   1.320 +    delete arctextmap[e];
   1.321 +  }
   1.322 +
   1.323 +  is_drawn=false;
   1.324 +}
   1.325 +
   1.326 +void DigraphDisplayerCanvas::setView(bool autoscale_p, bool zoomtrack_p, double width_p, double radius_p)
   1.327 +{
   1.328 +  autoscale=autoscale_p;
   1.329 +  arc_width=width_p;
   1.330 +  radius_size=radius_p;
   1.331 +
   1.332 +  if((!zoomtrack) && zoomtrack_p)
   1.333 +    {
   1.334 +      fixed_zoom_factor=get_pixels_per_unit();
   1.335 +    }
   1.336 +
   1.337 +  zoomtrack=zoomtrack_p;
   1.338 +
   1.339 +  propertyChange(false, N_RADIUS);
   1.340 +  propertyChange(true, E_WIDTH);
   1.341 +}
   1.342 +
   1.343 +void DigraphDisplayerCanvas::getView(bool & autoscale_p, bool & zoomtrack_p, double& width_p, double& radius_p)
   1.344 +{
   1.345 +  autoscale_p=autoscale;
   1.346 +  zoomtrack_p=zoomtrack;
   1.347 +  width_p=arc_width;
   1.348 +  radius_p=radius_size;
   1.349 +}
   1.350 +
   1.351 +void DigraphDisplayerCanvas::reDesignDigraph()
   1.352 +{
   1.353 +  MapStorage& ms = *mytab.mapstorage;
   1.354 +  NodeIt firstnode(ms.digraph);
   1.355 +  //is it not an empty digraph?
   1.356 +  if(firstnode!=INVALID)
   1.357 +    {
   1.358 +      double max_coord=50000;
   1.359 +      double min_dist=20;
   1.360 +      double init_vector_length=25;
   1.361 +
   1.362 +      if(!was_redesigned)
   1.363 +	{
   1.364 +	  NodeIt i(ms.digraph);
   1.365 +
   1.366 +	  dim2::Point<double> init(init_vector_length*rnd(),
   1.367 +				   init_vector_length*rnd());
   1.368 +	  moveNode(init.x, init.y, nodesmap[i], i);
   1.369 +	  was_redesigned=true;
   1.370 +	}
   1.371 +
   1.372 +      double attraction;
   1.373 +      double propulsation;
   1.374 +      int iterations;
   1.375 +
   1.376 +      ms.get_design_data(attraction, propulsation, iterations);
   1.377 +
   1.378 +      //iteration counter
   1.379 +      for(int l=0;l<iterations;l++)
   1.380 +	{
   1.381 +	  Digraph::NodeMap<double> x(ms.digraph);
   1.382 +	  Digraph::NodeMap<double> y(ms.digraph);
   1.383 +	  XYMap<Digraph::NodeMap<double> > actual_forces;
   1.384 +	  actual_forces.setXMap(x);
   1.385 +	  actual_forces.setYMap(y);
   1.386 +
   1.387 +	  //count actual force for each nodes
   1.388 +	  for (NodeIt i(ms.digraph); i!=INVALID; ++i)
   1.389 +	    {
   1.390 +	      //propulsation of nodes
   1.391 +	      for (NodeIt j(ms.digraph); j!=INVALID; ++j)
   1.392 +		{
   1.393 +		  if(i!=j)
   1.394 +		    {
   1.395 +		      lemon::dim2::Point<double> delta =
   1.396 +			(ms.getNodeCoords(i)-
   1.397 +			 ms.getNodeCoords(j));
   1.398 +
   1.399 +		      const double length_sqr=std::max(delta.normSquare(),min_dist);
   1.400 +
   1.401 +		      //normalize vector
   1.402 +		      delta/=sqrt(length_sqr);
   1.403 +
   1.404 +		      //calculating propulsation strength
   1.405 +		      //greater distance menas smaller propulsation strength
   1.406 +		      delta*=propulsation/length_sqr;
   1.407 +		    
   1.408 +		      actual_forces.set(i,(actual_forces[i]+delta));
   1.409 +		    }
   1.410 +		}
   1.411 +            //attraction of nodes, to which actual node is bound
   1.412 +            for(OutArcIt ei(ms.digraph,i);ei!=INVALID;++ei)
   1.413 +              {
   1.414 +                lemon::dim2::Point<double> delta =
   1.415 +                  (ms.getNodeCoords(i)-
   1.416 +                   ms.getNodeCoords(ms.digraph.target(ei)));
   1.417 +
   1.418 +                //calculating attraction strength
   1.419 +                //greater distance means greater strength
   1.420 +                delta*=attraction;
   1.421 +
   1.422 +                actual_forces.set(i,actual_forces[i]-delta);
   1.423 +              }
   1.424 +                    for(InArcIt ei(ms.digraph,i);ei!=INVALID;++ei)
   1.425 +              {
   1.426 +                lemon::dim2::Point<double> delta =
   1.427 +                  (ms.getNodeCoords(i)-
   1.428 +                   ms.getNodeCoords(ms.digraph.source(ei)));
   1.429 +
   1.430 +                //calculating attraction strength
   1.431 +                //greater distance means greater strength
   1.432 +                delta*=attraction;
   1.433 +
   1.434 +                actual_forces.set(i,actual_forces[i]-delta);
   1.435 +              }
   1.436 +	    }
   1.437 +	  for (NodeIt i(ms.digraph); i!=INVALID; ++i)
   1.438 +	    {
   1.439 +	      if((ms.getNodeCoords(i).x)+actual_forces[i].x>max_coord)
   1.440 +		{
   1.441 +		  actual_forces[i].x=max_coord-(ms.getNodeCoords(i).x);
   1.442 +		  std::cout << "Correction! " << ((ms.getNodeCoords(i).x)+actual_forces[i].x) << std::endl;
   1.443 +		}
   1.444 +	      else if((ms.getNodeCoords(i).x)+actual_forces[i].x<(0-max_coord))
   1.445 +		{
   1.446 +		  actual_forces[i].x=0-max_coord-(ms.getNodeCoords(i).x);
   1.447 +		  std::cout << "Correction! " << ((ms.getNodeCoords(i).x)+actual_forces[i].x) << std::endl;
   1.448 +		}
   1.449 +	      if((ms.getNodeCoords(i).y)+actual_forces[i].y>max_coord)
   1.450 +		{
   1.451 +		  actual_forces[i].y=max_coord-(ms.getNodeCoords(i).y);
   1.452 +		  std::cout << "Correction! " << ((ms.getNodeCoords(i).y)+actual_forces[i].y) << std::endl;
   1.453 +		}
   1.454 +	      else if((ms.getNodeCoords(i).y)+actual_forces[i].y<(0-max_coord))
   1.455 +		{
   1.456 +		  actual_forces[i].y=0-max_coord-(ms.getNodeCoords(i).y);
   1.457 +		  std::cout << "Correction! " << ((ms.getNodeCoords(i).y)+actual_forces[i].y) << std::endl;
   1.458 +		}
   1.459 +	      moveNode(actual_forces[i].x, actual_forces[i].y, nodesmap[i], i);
   1.460 +	    }
   1.461 +	}
   1.462 +    }
   1.463 +}
   1.464 +