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