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