COIN-OR::LEMON - Graph Library

source: glemon-0.x/graph_displayer_canvas.cc @ 192:9d7489e8921e

Last change on this file since 192:9d7489e8921e was 190:2cac5b936a2b, checked in by Hegyi Péter, 18 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
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  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;
333
334      if(!was_redesigned)
335        {
336          NodeIt i((mytab.mapstorage).graph);
337
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        }
343
344      double attraction;
345      double propulsation;
346      int iterations;
347
348      (mytab.mapstorage).get_design_data(attraction, propulsation, iterations);
349
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);
358
359          //count actual force for each nodes
360          for (NodeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
361            {
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)
385                {
386                  lemon::dim2::Point<double> delta =
387                    ((mytab.mapstorage).coords[i]-
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);
409                }
410            }
411          for (NodeIt i((mytab.mapstorage).graph); i!=INVALID; ++i)
412            {
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);
434            }
435        }
436    }
437}
438
Note: See TracBrowser for help on using the repository browser.