COIN-OR::LEMON - Graph Library

source: lemon-0.x/src/work/alpar/graph_to_eps.cc @ 1059:bd97feae7d90

Last change on this file since 1059:bd97feae7d90 was 1055:f901ff02b2d7, checked in by Alpar Juttner, 19 years ago

graphToEps also accepts an output file name parameter.

File size: 14.5 KB
Line 
1#include <iostream>
2#include <fstream>
3#include <algorithm>
4#include<math.h>
5
6#include<lemon/xy.h>
7#include<lemon/maps.h>
8#include<lemon/list_graph.h>
9
10
11///\file \ingroup misc
12///Simple graph drawer
13
14namespace lemon {
15
16///Data structure representing RGB colors.
17
18///Data structure representing RGB colors.
19///\ingroup misc
20class Color
21{
22  double _r,_g,_b;
23public:
24  ///Default constructor
25  Color() {}
26  ///Constructor
27  Color(double r,double g,double b) :_r(r),_g(g),_b(b) {};
28  ///Returns the red component
29  double getR() {return _r;}
30  ///Returns the green component
31  double getG() {return _g;}
32  ///Returns the blue component
33  double getB() {return _b;}
34  ///Set the color components
35  void set(double r,double g,double b) { _r=r;_g=g;_b=b; };
36};
37 
38///Default traits class of \ref GraphToEps
39
40///Default traits class of \ref GraphToEps
41///
42///\c G is the type of the underlying graph.
43template<class G>
44struct DefaultGraphToEpsTraits
45{
46  typedef G Graph;
47  typedef typename Graph::Node Node;
48  typedef typename Graph::NodeIt NodeIt;
49  typedef typename Graph::Edge Edge;
50  typedef typename Graph::EdgeIt EdgeIt;
51  typedef typename Graph::InEdgeIt InEdgeIt;
52  typedef typename Graph::OutEdgeIt OutEdgeIt;
53 
54
55  const Graph &g;
56
57  std::ostream& os;
58 
59  ConstMap<typename Graph::Node,xy<double> > _coords;
60  ConstMap<typename Graph::Node,double > _nodeSizes;
61
62  ConstMap<typename Graph::Node,Color > _nodeColors;
63  ConstMap<typename Graph::Edge,Color > _edgeColors;
64
65  ConstMap<typename Graph::Edge,double > _edgeWidths;
66 
67  double _edgeWidthScale;
68 
69  double _nodeScale;
70  double _xBorder, _yBorder;
71  double _scale;
72  double _nodeBorderQuotient;
73 
74  bool _drawArrows;
75  double _arrowLength, _arrowWidth;
76 
77  bool _enableParallel;
78
79  bool _pleaseRemoveOsStream;
80  ///Constructor
81
82  ///Constructor
83  ///\param _g is a reference to the graph to be printed
84  ///\param _os is a reference to the output stream.
85  ///\param _os is a reference to the output stream.
86  ///\param _pros If it is \c true, then the \c ostream referenced by \c _os
87  ///will be explicitly deallocated by the destructor.
88  ///By default it is <tt>std::cout</tt>
89  DefaultGraphToEpsTraits(const G &_g,std::ostream& _os=std::cout,
90                          bool _pros=false) :
91    g(_g), os(_os),
92    _coords(xy<double>(1,1)), _nodeSizes(1.0),
93    _nodeColors(Color(1,1,1)), _edgeColors(Color(0,0,0)),
94    _edgeWidths(1), _edgeWidthScale(0.3),
95    _nodeScale(1.0), _xBorder(10), _yBorder(10), _scale(1.0),
96    _nodeBorderQuotient(.1),
97    _drawArrows(false), _arrowLength(1), _arrowWidth(0.3),
98    _enableParallel(false), _pleaseRemoveOsStream(_pros) {}
99};
100
101///Helper class to implement the named parameters of \ref graphToEps()
102
103///Helper class to implement the named parameters of \ref graphToEps()
104///\todo Is 'helper class' a good name for this?
105///
106template<class T> class GraphToEps : public T
107{
108  typedef typename T::Graph Graph;
109  typedef typename Graph::Node Node;
110  typedef typename Graph::NodeIt NodeIt;
111  typedef typename Graph::Edge Edge;
112  typedef typename Graph::EdgeIt EdgeIt;
113  typedef typename Graph::InEdgeIt InEdgeIt;
114  typedef typename Graph::OutEdgeIt OutEdgeIt;
115
116  bool dontPrint;
117
118  class edgeLess {
119    const Graph &g;
120  public:
121    edgeLess(const Graph &_g) : g(_g) {}
122    bool operator()(Edge a,Edge b) const
123    {
124      Node ai=min(g.source(a),g.target(a));
125      Node aa=max(g.source(a),g.target(a));
126      Node bi=min(g.source(b),g.target(b));
127      Node ba=max(g.source(b),g.target(b));
128      return ai<bi ||
129        (ai==bi && (aa < ba ||
130                    (aa==ba && ai==g.source(a) && bi==g.target(b))));
131    }
132  };
133   
134public:
135  GraphToEps(const T &t) : T(t), dontPrint(false) {};
136 
137  template<class X> struct CoordsTraits : public T {
138    const X &_coords;
139    CoordsTraits(const T &t,const X &x) : T(t), _coords(x) {}
140  };
141  ///Sets the map of the node coordinates
142
143  ///Sets the map of the node coordinates.
144  ///\param x must be a node map with xy<double> or xy<int> values.
145  template<class X> GraphToEps<CoordsTraits<X> > coords(const X &x) {
146    dontPrint=true;
147    return GraphToEps<CoordsTraits<X> >(CoordsTraits<X>(*this,x));
148  }
149  template<class X> struct NodeSizesTraits : public T {
150    const X &_nodeSizes;
151    NodeSizesTraits(const T &t,const X &x) : T(t), _nodeSizes(x) {}
152  };
153  ///Sets the map of the node sizes
154
155  ///Sets the map of the node sizes
156  ///\param x must be a node map with \c double (or convertible) values.
157  template<class X> GraphToEps<NodeSizesTraits<X> > nodeSizes(const X &x)
158  {
159    dontPrint=true;
160    return GraphToEps<NodeSizesTraits<X> >(NodeSizesTraits<X>(*this,x));
161  }
162   template<class X> struct EdgeWidthsTraits : public T {
163    const X &_edgeWidths;
164    EdgeWidthsTraits(const T &t,const X &x) : T(t), _edgeWidths(x) {}
165  };
166  ///Sets the map of the edge widths
167
168  ///Sets the map of the edge widths
169  ///\param x must be a edge map with \c double (or convertible) values.
170  template<class X> GraphToEps<EdgeWidthsTraits<X> > edgeWidths(const X &x)
171  {
172    dontPrint=true;
173    return GraphToEps<EdgeWidthsTraits<X> >(EdgeWidthsTraits<X>(*this,x));
174  }
175
176  template<class X> struct NodeColorsTraits : public T {
177    const X &_nodeColors;
178    NodeColorsTraits(const T &t,const X &x) : T(t), _nodeColors(x) {}
179  };
180  ///Sets the map of the node colors
181
182  ///Sets the map of the node colors
183  ///\param x must be a node map with \ref Color values.
184  template<class X> GraphToEps<NodeColorsTraits<X> >
185  nodeColors(const X &x)
186  {
187    dontPrint=true;
188    return GraphToEps<NodeColorsTraits<X> >(NodeColorsTraits<X>(*this,x));
189  }
190  template<class X> struct EdgeColorsTraits : public T {
191    const X &_edgeColors;
192    EdgeColorsTraits(const T &t,const X &x) : T(t), _edgeColors(x) {}
193  };
194  ///Sets the map of the edge colors
195
196  ///Sets the map of the edge colors
197  ///\param x must be a edge map with \ref Color values.
198  template<class X> GraphToEps<EdgeColorsTraits<X> >
199  edgeColors(const X &x)
200  {
201    dontPrint=true;
202    return GraphToEps<EdgeColorsTraits<X> >(EdgeColorsTraits<X>(*this,x));
203  }
204  ///Sets a global scale factor for node sizes
205
206  ///Sets a global scale factor for node sizes
207  ///
208  GraphToEps<T> &nodeScale(double d) {_nodeScale=d;return *this;}
209  ///Sets a global scale factor for edge widths
210
211  ///Sets a global scale factor for edge widths
212  ///
213  GraphToEps<T> &edgeWidthScale(double d) {_edgeWidthScale=d;return *this;}
214  ///Sets a global scale factor for the whole picture
215
216  ///Sets a global scale factor for the whole picture
217  ///
218  GraphToEps<T> &scale(double d) {_scale=d;return *this;}
219  ///Sets the width of the border around the picture
220
221  ///Sets the width of the border around the picture
222  ///
223  GraphToEps<T> &border(double b) {_xBorder=_yBorder=b;return *this;}
224  ///Sets the width of the border around the picture
225
226  ///Sets the width of the border around the picture
227  ///
228  GraphToEps<T> &border(double x, double y) {
229    _xBorder=x;_yBorder=y;return *this;
230  }
231  ///Sets whether to draw arrows
232
233  ///Sets whether to draw arrows
234  ///
235  GraphToEps<T> &drawArrows(bool b=true) {_drawArrows=b;return *this;}
236  ///Sets the length of the arrowheads
237
238  ///Sets the length of the arrowheads
239  ///
240  GraphToEps<T> &arrowLength(double d) {_arrowLength*=d;return *this;}
241  ///Sets the width of the arrowheads
242
243  ///Sets the width of the arrowheads
244  ///
245  GraphToEps<T> &arrowWidth(double d) {_arrowWidth*=d;return *this;}
246 
247  ///Enables parallel edges
248
249  ///Enables parallel edges
250  ///\todo Unimplemented
251  GraphToEps<T> &enableParallel(bool b=true) {_enableParallel=b;return *this;}
252 
253  ~GraphToEps()
254  {
255    if(dontPrint) return;
256   
257    os << "%!PS-Adobe-2.0 EPSF-2.0\n";
258    //\todo: Chech whether the graph is empty.
259    BoundingBox<double> bb;
260    for(NodeIt n(g);n!=INVALID;++n) {
261      double ns=_nodeSizes[n]*_nodeScale;
262      xy<double> p(ns,ns);
263      bb+=p+_coords[n];
264      bb+=-p+_coords[n];
265      }
266    os << "%%BoundingBox: "
267         << bb.left()*  _scale-_xBorder << ' '
268         << bb.bottom()*_scale-_yBorder << ' '
269         << bb.right()* _scale+_xBorder << ' '
270         << bb.top()*   _scale+_yBorder << '\n';
271    //x1 y1 x2 y2 cr cg cb w
272    os << "/l { setlinewidth setrgbcolor newpath moveto lineto stroke } bind def\n";
273    os << "/c { newpath dup 3 index add 2 index moveto 0 360 arc } bind def\n";
274    // x y r cr cg cb
275    os << "/n { setrgbcolor 2 index 2 index 2 index c fill\n"
276         << "     0 0 0 setrgbcolor dup "
277         << _nodeBorderQuotient << " mul setlinewidth "
278         << 1+_nodeBorderQuotient/2 << " div c stroke\n"
279         << "   } bind def\n";
280    os << "/arrl " << _arrowLength << " def\n";
281    os << "/arrw " << _arrowWidth << " def\n";
282    // l dx_norm dy_norm
283    os << "/lrl { 2 index mul exch 2 index mul exch rlineto pop} bind def\n";
284    //len w dx_norm dy_norm x1 y1 cr cg cb
285    os << "/arr { setrgbcolor /y1 exch def /x1 exch def /dy exch def /dx exch def\n"
286         << "       /w exch def /len exch def\n"
287      //         << "       0.1 setlinewidth x1 y1 moveto dx len mul dy len mul rlineto stroke"
288         << "       newpath x1 dy w 2 div mul add y1 dx w 2 div mul sub moveto\n"
289         << "       len w sub arrl sub dx dy lrl\n"
290         << "       arrw dy dx neg lrl\n"
291         << "       dx arrl w add mul dy w 2 div arrw add mul sub\n"
292         << "       dy arrl w add mul dx w 2 div arrw add mul add rlineto\n"
293         << "       dx arrl w add mul neg dy w 2 div arrw add mul sub\n"
294         << "       dy arrl w add mul neg dx w 2 div arrw add mul add rlineto\n"
295         << "       arrw dy dx neg lrl\n"
296         << "       len w sub arrl sub neg dx dy lrl\n"
297         << "       closepath fill } bind def\n";
298    os << "\ngsave\n";
299    if(_scale!=1.0) os << _scale << " dup scale\n";
300   
301    os << "%Edges:\ngsave\n";
302   
303    vector<Edge> el;
304    if(_enableParallel) {
305      for(EdgeIt e(g);e!=INVALID;++e) el.push_back(e);
306      sort(el.begin(),el.end(),edgeLess(g));
307    }
308   
309    for(NodeIt n(g);n!=INVALID;++n)
310      for(OutEdgeIt e(g,n);e!=INVALID;++e)
311        if(_drawArrows) {
312          xy<double> d(_coords[g.target(e)]-_coords[g.source(e)]);
313          double l=sqrt(d.normSquare());
314          d/=l;
315          xy<double> x1(d*_nodeScale*_nodeSizes[g.source(e)]+
316                        _coords[g.source(e)]);
317          os << l-(_nodeSizes[g.source(e)]+
318                     _nodeSizes[g.target(e)])*_nodeScale << ' '
319               << _edgeWidths[e]*_edgeWidthScale << ' '
320               << d.x << ' ' << d.y << ' '
321               << x1.x << ' ' << x1.y << ' '
322               << _edgeColors[e].getR() << ' '
323               << _edgeColors[e].getG() << ' '
324               << _edgeColors[e].getB() << " arr\n";
325        }
326        else os << _coords[g.source(e)].x << ' '
327                  << _coords[g.source(e)].y << ' '
328                  << _coords[g.target(e)].x << ' '
329                  << _coords[g.target(e)].y << ' '
330                  << _edgeColors[e].getR() << ' '
331                  << _edgeColors[e].getG() << ' '
332                  << _edgeColors[e].getB() << ' '
333                  << _edgeWidths[e]*_edgeWidthScale << " l\n";
334    os << "grestore\n%Nodes:\ngsave\n";
335    for(NodeIt n(g);n!=INVALID;++n)
336      os << _coords[n].x << ' ' << _coords[n].y << ' '
337           << _nodeSizes[n]*_nodeScale << ' '
338           << _nodeColors[n].getR() << ' '
339           << _nodeColors[n].getG() << ' '
340           << _nodeColors[n].getB() << " n\n";
341    os << "grestore\ngrestore\n";
342
343
344    //CleanUp:
345    if(_pleaseRemoveOsStream) {delete &os;}
346  }
347};
348
349
350///Generates an EPS file from a graph
351
352///\ingroup misc
353///Generates an EPS file from a graph.
354///\param g is a reference to the graph to be printed
355///\param os is a reference to the output stream.
356///By default it is <tt>std::cout</tt>
357///
358///This function also has a lot of \ref named-templ-param "named parameters",
359///they are declared as the members of class \ref GraphToEps. The following
360///example shows how to use these parameters.
361///\code
362/// graphToEps(g).scale(10).coords(coords)
363///              .nodeScale(2).nodeSizes(sizes)
364///              .edgeWidthScale(.4);
365///\endcode
366///\sa GraphToEps
367template<class G>
368GraphToEps<DefaultGraphToEpsTraits<G> >
369graphToEps(G &g,std::ostream& os=std::cout)
370{
371  return
372    GraphToEps<DefaultGraphToEpsTraits<G> >(DefaultGraphToEpsTraits<G>(g,os));
373}
374 
375///Generates an EPS file from a graph
376
377///\ingroup misc
378///Generates an EPS file from a graph.
379///\param g is a reference to the graph to be printed
380///\param file_name is the output file_name.
381///
382///This function also has a lot of \ref named-templ-param "named parameters",
383///they are declared as the members of class \ref GraphToEps. The following
384///example shows how to use these parameters.
385///\code
386/// graphToEps(g).scale(10).coords(coords)
387///              .nodeScale(2).nodeSizes(sizes)
388///              .edgeWidthScale(.4);
389///\endcode
390///\sa GraphToEps
391///\todo Avoid duplicated documentation
392///\bug Exception handling is missing? (Or we can just ignore it?)
393template<class G>
394GraphToEps<DefaultGraphToEpsTraits<G> >
395graphToEps(G &g,char *file_name)
396{
397  return GraphToEps<DefaultGraphToEpsTraits<G> >
398    (DefaultGraphToEpsTraits<G>(g,*new ofstream(file_name),true));
399}
400
401
402}
403
404using namespace lemon;
405
406class ColorSet : public MapBase<int,Color>
407{
408public:
409  Color operator[](int i) const
410  {
411    switch(i%8){
412    case 0: return Color(0,0,0);
413    case 1: return Color(1,0,0);
414    case 2: return Color(0,1,0);
415    case 3: return Color(0,0,1);
416    case 4: return Color(1,1,0);
417    case 5: return Color(1,0,1);
418    case 6: return Color(0,1,1);
419    case 7: return Color(1,1,1);
420    }
421    return Color(0,0,0);
422  }
423} colorSet;
424
425int main()
426{
427  ListGraph g;
428  typedef ListGraph::Node Node;
429  typedef ListGraph::NodeIt NodeIt;
430  typedef ListGraph::Edge Edge;
431  typedef xy<int> Xy;
432 
433  Node n1=g.addNode();
434  Node n2=g.addNode();
435  Node n3=g.addNode();
436  Node n4=g.addNode();
437  Node n5=g.addNode();
438
439  ListGraph::NodeMap<Xy> coords(g);
440  ListGraph::NodeMap<double> sizes(g);
441  ListGraph::NodeMap<int> colors(g);
442  ListGraph::EdgeMap<int> ecolors(g);
443  ListGraph::EdgeMap<int> widths(g);
444 
445  coords[n1]=Xy(50,50);  sizes[n1]=1; colors[n1]=1;
446  coords[n2]=Xy(50,70);  sizes[n2]=2; colors[n2]=2;
447  coords[n3]=Xy(70,70);  sizes[n3]=1; colors[n3]=3;
448  coords[n4]=Xy(70,50);  sizes[n4]=2; colors[n4]=4;
449  coords[n5]=Xy(85,60);  sizes[n5]=3; colors[n5]=5;
450 
451  Edge e;
452
453  e=g.addEdge(n1,n2); ecolors[e]=0; widths[e]=1;
454  e=g.addEdge(n2,n3); ecolors[e]=0; widths[e]=1;
455  e=g.addEdge(n3,n5); ecolors[e]=0; widths[e]=3;
456  e=g.addEdge(n5,n4); ecolors[e]=0; widths[e]=1;
457  e=g.addEdge(n4,n1); ecolors[e]=0; widths[e]=1;
458  e=g.addEdge(n2,n4); ecolors[e]=1; widths[e]=2;
459  e=g.addEdge(n3,n4); ecolors[e]=2; widths[e]=1;
460 
461  graphToEps(g,"proba.eps").scale(10).coords(coords).
462    nodeScale(2).nodeSizes(sizes).
463    nodeColors(composeMap(colorSet,colors)).
464    edgeColors(composeMap(colorSet,ecolors)).
465    edgeWidthScale(.4).edgeWidths(widths);
466  graphToEps(g,"proba_arr.eps").scale(10).coords(coords).
467    nodeScale(2).nodeSizes(sizes).
468    nodeColors(composeMap(colorSet,colors)).
469    edgeColors(composeMap(colorSet,ecolors)).
470    edgeWidthScale(.4).edgeWidths(widths).
471    drawArrows().arrowWidth(1).arrowLength(1)
472    ;
473}
Note: See TracBrowser for help on using the repository browser.