COIN-OR::LEMON - Graph Library

source: glemon-0.x/graph_displayer_canvas.cc @ 184:4e8704aae278

Last change on this file since 184:4e8704aae278 was 184:4e8704aae278, checked in by Akos Ladanyi, 13 years ago

Added support for setting the background form an image file.

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