COIN-OR::LEMON - Graph Library

source: glemon-0.x/graph_displayer_canvas.cc @ 160:14a76109b561

Last change on this file since 160:14a76109b561 was 160:14a76109b561, checked in by Hegyi Péter, 18 years ago

Node antigravity and edge elasticity based graph layout redesigner.

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