COIN-OR::LEMON - Graph Library

source: glemon-0.x/graph_displayer_canvas.cc @ 197:c1084e2bff10

Last change on this file since 197:c1084e2bff10 was 194:6b2b718420eb, checked in by Hegyi Péter, 17 years ago

Header reorganising

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