COIN-OR::LEMON - Graph Library

source: glemon-0.x/graph_displayer_canvas.cc @ 180:911c6ba0e3c8

Last change on this file since 180:911c6ba0e3c8 was 180:911c6ba0e3c8, checked in by Alpar Juttner, 17 years ago

Bugfix + polishing

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