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