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