COIN-OR::LEMON - Graph Library

source: lemon-0.x/src/work/alpar/graph_to_eps.cc @ 1050:bcc0766a7b86

Last change on this file since 1050:bcc0766a7b86 was 1050:bcc0766a7b86, checked in by Alpar Juttner, 18 years ago

Several new named parameters and documentation added to graphToEps().

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