COIN-OR::LEMON - Graph Library

source: glemon-0.x/graph_displayer_canvas.cc @ 190:2cac5b936a2b

Last change on this file since 190:2cac5b936a2b was 190:2cac5b936a2b, checked in by Hegyi Péter, 17 years ago

Working tooltips are added. No segmentation fault is occured if empty graphs are redesigned.

  • Property exe set to *
File size: 11.2 KB
RevLine 
[174]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
[53]19#include "graph_displayer_canvas.h"
[167]20#include <lemon/random.h>
[59]21#include <cmath>
[6]22
[96]23GraphDisplayerCanvas::GraphDisplayerCanvas(NoteBookTab & mainw) :
[94]24  nodesmap(mainw.mapstorage.graph), edgesmap(mainw.mapstorage.graph), edgetextmap(mainw.mapstorage.graph),
25  nodetextmap(mainw.mapstorage.graph), displayed_graph(*(root()), 0, 0),
[66]26  isbutton(0), active_item(NULL), target_item(NULL), nodemap_to_edit(""),
[160]27  edgemap_to_edit(""), autoscale(true), zoomtrack(false), radius_size(20), edge_width(10),
[184]28  was_redesigned(false), is_drawn(false), mytab(mainw),
29  background_set(false)
[6]30{
[187]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
[53]34  //base event handler is move tool
35  actual_handler=signal_event().connect(sigc::mem_fun(*this, &GraphDisplayerCanvas::moveEventHandler), false);
36  actual_tool=MOVE;
[34]37
[187]38
[53]39  active_node=INVALID;
40  active_edge=INVALID;
41  forming_edge=INVALID;
[184]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  }
[53]68}
[9]69
[53]70GraphDisplayerCanvas::~GraphDisplayerCanvas()
71{
[96]72  for (NodeIt n((mytab.mapstorage).graph); n != INVALID; ++n)
[94]73    {
74      delete nodesmap[n];
75      delete nodetextmap[n];
76    }
77 
[96]78  for (EdgeIt e((mytab.mapstorage).graph); e != INVALID; ++e)
[94]79    {
80      delete edgesmap[e];
81      delete edgetextmap[e];
82    }
83}
[6]84
[94]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
[118]113void GraphDisplayerCanvas::propertyUpdate(Node node, int prop)
[94]114{
[96]115  std::string mapname=mytab.getActiveNodeMap(prop);
[94]116
[172]117  if(is_drawn)
[94]118    {
[172]119      if(mapname!="")
[94]120        {
[172]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;   
[94]142          switch(prop)
143            {
144            case N_RADIUS:
[172]145              resetNodeRadius(node);
[94]146              break;
147            case N_COLOR:
[172]148              resetNodeColor(node);
[94]149              break;
150            case N_TEXT:
[172]151              resetNodeText(node);
[94]152              break;
153            default:
154              std::cerr<<"Error\n";
155            }
156        }
157    }
158}
159
[118]160void GraphDisplayerCanvas::propertyUpdate(Edge edge, int prop)
[94]161{
[96]162  std::string mapname=mytab.getActiveEdgeMap(prop);
[94]163
[172]164  if(is_drawn)
[94]165    {
[172]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==""
[94]187        {
188          switch(prop)
189            {
190            case E_WIDTH:
[172]191              resetEdgeWidth(edge);
[94]192              break;
193            case E_COLOR:
[172]194              resetEdgeColor(edge);
[94]195              break;
196            case E_TEXT:
[172]197              resetEdgeText(edge);
[94]198              break;
199            default:
200              std::cerr<<"Error\n";
201            }
202        }
203    }
[53]204}
205
206void GraphDisplayerCanvas::drawGraph()
207{
[6]208  //first edges are drawn, to hide joining with nodes later
209
[96]210  for (EdgeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
[6]211  {
[151]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    }
[6]220    //initializing edge-text as well, to empty string
221
[98]222    XY text_pos=mytab.mapstorage.arrow_pos[i];
223    text_pos+=(XY(10,10));
[25]224
225    edgetextmap[i]=new Gnome::Canvas::Text(displayed_graph, text_pos.x, text_pos.y, "");
[28]226    edgetextmap[i]->property_fill_color().set_value("darkgreen");
[149]227    edgetextmap[i]->signal_event().connect(sigc::mem_fun(*this, &GraphDisplayerCanvas::mapEditEventHandler), false);
[63]228    edgetextmap[i]->raise_to_top();
[6]229  }
230
231  //afterwards nodes come to be drawn
232
[96]233  for (NodeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
[6]234  {
235    //drawing bule nodes, with black line around them
236
[53]237    nodesmap[i]=new Gnome::Canvas::Ellipse(
238        displayed_graph,
[96]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);
[6]243    *(nodesmap[i]) << Gnome::Canvas::Properties::fill_color("blue");
244    *(nodesmap[i]) << Gnome::Canvas::Properties::outline_color("black");
[63]245    nodesmap[i]->raise_to_top();
[28]246
247    //initializing edge-text as well, to empty string
248
[150]249    XY text_pos(
[96]250        ((mytab.mapstorage).coords[i].x+node_property_defaults[N_RADIUS]+5),
251        ((mytab.mapstorage).coords[i].y+node_property_defaults[N_RADIUS]+5));
[28]252
[53]253    nodetextmap[i]=new Gnome::Canvas::Text(displayed_graph,
254        text_pos.x, text_pos.y, "");
[28]255    nodetextmap[i]->property_fill_color().set_value("darkblue");
[149]256    nodetextmap[i]->signal_event().connect(sigc::mem_fun(*this, &GraphDisplayerCanvas::mapEditEventHandler), false);
[63]257    nodetextmap[i]->raise_to_top();
[6]258  }
259
[172]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
[6]275  updateScrollRegion();
276}
277
[53]278void GraphDisplayerCanvas::clear()
[6]279{
[53]280  active_node=INVALID;
281  active_edge=INVALID;
282  forming_edge=INVALID;
[6]283
[96]284  for (NodeIt n((mytab.mapstorage).graph); n != INVALID; ++n)
[6]285  {
[53]286    delete nodesmap[n];
287    delete nodetextmap[n];
[6]288  }
289
[96]290  for (EdgeIt e((mytab.mapstorage).graph); e != INVALID; ++e)
[53]291  {
292    delete edgesmap[e];
293    delete edgetextmap[e];
294  }
[172]295
296  is_drawn=false;
[6]297}
[154]298
[157]299void GraphDisplayerCanvas::setView(bool autoscale_p, bool zoomtrack_p, double width_p, double radius_p)
[154]300{
301  autoscale=autoscale_p;
[157]302  edge_width=width_p;
303  radius_size=radius_p;
[156]304
305  if((!zoomtrack) && zoomtrack_p)
306    {
307      fixed_zoom_factor=get_pixels_per_unit();
308    }
309
310  zoomtrack=zoomtrack_p;
311
[154]312  propertyChange(false, N_RADIUS);
[157]313  propertyChange(true, E_WIDTH);
[154]314}
315
[157]316void GraphDisplayerCanvas::getView(bool & autoscale_p, bool & zoomtrack_p, double& width_p, double& radius_p)
[154]317{
318  autoscale_p=autoscale;
[156]319  zoomtrack_p=zoomtrack;
[157]320  width_p=edge_width;
321  radius_p=radius_size;
[154]322}
[160]323
324void GraphDisplayerCanvas::reDesignGraph()
325{
[190]326  NodeIt firstnode((mytab.mapstorage).graph);
327  //is it not an empty graph?
328  if(firstnode!=INVALID)
329    {
330      double max_coord=50000;
331      double min_dist=20;
332      double init_vector_length=25;
[166]333
[190]334      if(!was_redesigned)
335        {
336          NodeIt i((mytab.mapstorage).graph);
[167]337
[190]338          dim2::Point<double> init(init_vector_length*rnd(),
339                                   init_vector_length*rnd());
340          moveNode(init.x, init.y, nodesmap[i], i);
341          was_redesigned=true;
342        }
[177]343
[190]344      double attraction;
345      double propulsation;
346      int iterations;
[177]347
[190]348      (mytab.mapstorage).get_design_data(attraction, propulsation, iterations);
[160]349
[190]350      //iteration counter
351      for(int l=0;l<iterations;l++)
352        {
353          Graph::NodeMap<double> x(mytab.mapstorage.graph);
354          Graph::NodeMap<double> y(mytab.mapstorage.graph);
355          XYMap<Graph::NodeMap<double> > actual_forces;
356          actual_forces.setXMap(x);
357          actual_forces.setYMap(y);
[160]358
[190]359          //count actual force for each nodes
360          for (NodeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
[160]361            {
[190]362              //propulsation of nodes
363              for (NodeIt j((mytab.mapstorage).graph); j!=INVALID; ++j)
364                {
365                  if(i!=j)
366                    {
367                      lemon::dim2::Point<double> delta =
368                        ((mytab.mapstorage).coords[i]-
369                         (mytab.mapstorage).coords[j]);
370
371                      const double length_sqr=std::max(delta.normSquare(),min_dist);
372
373                      //normalize vector
374                      delta/=sqrt(length_sqr);
375
376                      //calculating propulsation strength
377                      //greater distance menas smaller propulsation strength
378                      delta*=propulsation/length_sqr;
379                   
380                      actual_forces.set(i,(actual_forces[i]+delta));
381                    }
382                }
383              //attraction of nodes, to which actual node is bound
384              for(OutEdgeIt ei((mytab.mapstorage).graph,i);ei!=INVALID;++ei)
[160]385                {
[180]386                  lemon::dim2::Point<double> delta =
387                    ((mytab.mapstorage).coords[i]-
[190]388                     (mytab.mapstorage).coords[mytab.mapstorage.
389                                               graph.target(ei)]);
390               
391                  //calculating attraction strength
392                  //greater distance means greater strength
393                  delta*=attraction;
394               
395                  actual_forces.set(i,actual_forces[i]-delta);
396                }
397              for(InEdgeIt ei((mytab.mapstorage).graph,i);ei!=INVALID;++ei)
398                {
399                  lemon::dim2::Point<double> delta =
400                    ((mytab.mapstorage).coords[i]-
401                     (mytab.mapstorage).coords[mytab.mapstorage.
402                                               graph.source(ei)]);
403               
404                  //calculating attraction strength
405                  //greater distance means greater strength
406                  delta*=attraction;
407               
408                  actual_forces.set(i,actual_forces[i]-delta);
[160]409                }
410            }
[190]411          for (NodeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
[160]412            {
[190]413              if(((mytab.mapstorage).coords[i].x)+actual_forces[i].x>max_coord)
414                {
415                  actual_forces[i].x=max_coord-((mytab.mapstorage).coords[i].x);
416                  std::cout << "Correction! " << (((mytab.mapstorage).coords[i].x)+actual_forces[i].x) << std::endl;
417                }
418              else if(((mytab.mapstorage).coords[i].x)+actual_forces[i].x<(0-max_coord))
419                {
420                  actual_forces[i].x=0-max_coord-((mytab.mapstorage).coords[i].x);
421                  std::cout << "Correction! " << (((mytab.mapstorage).coords[i].x)+actual_forces[i].x) << std::endl;
422                }
423              if(((mytab.mapstorage).coords[i].y)+actual_forces[i].y>max_coord)
424                {
425                  actual_forces[i].y=max_coord-((mytab.mapstorage).coords[i].y);
426                  std::cout << "Correction! " << (((mytab.mapstorage).coords[i].y)+actual_forces[i].y) << std::endl;
427                }
428              else if(((mytab.mapstorage).coords[i].y)+actual_forces[i].y<(0-max_coord))
429                {
430                  actual_forces[i].y=0-max_coord-((mytab.mapstorage).coords[i].y);
431                  std::cout << "Correction! " << (((mytab.mapstorage).coords[i].y)+actual_forces[i].y) << std::endl;
432                }
433              moveNode(actual_forces[i].x, actual_forces[i].y, nodesmap[i], i);
[160]434            }
435        }
436    }
437}
438
Note: See TracBrowser for help on using the repository browser.