COIN-OR::LEMON - Graph Library

source: glemon-0.x/graph_displayer_canvas.cc @ 187:b465e2c34f23

Last change on this file since 187:b465e2c34f23 was 187:b465e2c34f23, checked in by Hegyi Péter, 13 years ago

Zoom is now available with mouse-wheel.

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