1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/src/lemon/graph_to_eps.h Tue Jan 11 09:15:25 2005 +0000
1.3 @@ -0,0 +1,597 @@
1.4 +/* -*- C++ -*-
1.5 + * src/lemon/graph_to_eps.h - Part of LEMON, a generic C++ optimization library
1.6 + *
1.7 + * Copyright (C) 2004 Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
1.8 + * (Egervary Combinatorial Optimization Research Group, EGRES).
1.9 + *
1.10 + * Permission to use, modify and distribute this software is granted
1.11 + * provided that this copyright notice appears in all copies. For
1.12 + * precise terms see the accompanying LICENSE file.
1.13 + *
1.14 + * This software is provided "AS IS" with no warranty of any kind,
1.15 + * express or implied, and with no claim as to its suitability for any
1.16 + * purpose.
1.17 + *
1.18 + */
1.19 +
1.20 +#ifndef LEMON_GRAPH_TO_EPS_H
1.21 +#define LEMON_GRAPH_TO_EPS_H
1.22 +
1.23 +#include<iostream>
1.24 +#include<fstream>
1.25 +#include<sstream>
1.26 +#include<algorithm>
1.27 +#include<vector>
1.28 +
1.29 +#include<lemon/xy.h>
1.30 +#include<lemon/maps.h>
1.31 +#include<lemon/bezier.h>
1.32 +
1.33 +///\ingroup misc
1.34 +///\file
1.35 +///\brief Simple graph drawer
1.36 +///
1.37 +///\author Alpar Juttner
1.38 +
1.39 +namespace lemon {
1.40 +
1.41 +///Data structure representing RGB colors.
1.42 +
1.43 +///Data structure representing RGB colors.
1.44 +///\ingroup misc
1.45 +class Color
1.46 +{
1.47 + double _r,_g,_b;
1.48 +public:
1.49 + ///Default constructor
1.50 + Color() {}
1.51 + ///Constructor
1.52 + Color(double r,double g,double b) :_r(r),_g(g),_b(b) {};
1.53 + ///Returns the red component
1.54 + double getR() {return _r;}
1.55 + ///Returns the green component
1.56 + double getG() {return _g;}
1.57 + ///Returns the blue component
1.58 + double getB() {return _b;}
1.59 + ///Set the color components
1.60 + void set(double r,double g,double b) { _r=r;_g=g;_b=b; };
1.61 +};
1.62 +
1.63 +///Default traits class of \ref GraphToEps
1.64 +
1.65 +///Default traits class of \ref GraphToEps
1.66 +///
1.67 +///\c G is the type of the underlying graph.
1.68 +template<class G>
1.69 +struct DefaultGraphToEpsTraits
1.70 +{
1.71 + typedef G Graph;
1.72 + typedef typename Graph::Node Node;
1.73 + typedef typename Graph::NodeIt NodeIt;
1.74 + typedef typename Graph::Edge Edge;
1.75 + typedef typename Graph::EdgeIt EdgeIt;
1.76 + typedef typename Graph::InEdgeIt InEdgeIt;
1.77 + typedef typename Graph::OutEdgeIt OutEdgeIt;
1.78 +
1.79 +
1.80 + const Graph &g;
1.81 +
1.82 + std::ostream& os;
1.83 +
1.84 + ConstMap<typename Graph::Node,xy<double> > _coords;
1.85 + ConstMap<typename Graph::Node,double > _nodeSizes;
1.86 +
1.87 + ConstMap<typename Graph::Node,Color > _nodeColors;
1.88 + ConstMap<typename Graph::Edge,Color > _edgeColors;
1.89 +
1.90 + ConstMap<typename Graph::Edge,double > _edgeWidths;
1.91 +
1.92 + double _edgeWidthScale;
1.93 +
1.94 + double _nodeScale;
1.95 + double _xBorder, _yBorder;
1.96 + double _scale;
1.97 + double _nodeBorderQuotient;
1.98 +
1.99 + bool _drawArrows;
1.100 + double _arrowLength, _arrowWidth;
1.101 +
1.102 + bool _showNodes, _showEdges;
1.103 +
1.104 + bool _enableParallel;
1.105 + double _parEdgeDist;
1.106 +
1.107 + bool _showNodeText;
1.108 + ConstMap<typename Graph::Node,bool > _nodeTexts;
1.109 + double _nodeTextSize;
1.110 +
1.111 + bool _undir;
1.112 + bool _pleaseRemoveOsStream;
1.113 + ///Constructor
1.114 +
1.115 + ///Constructor
1.116 + ///\param _g is a reference to the graph to be printed
1.117 + ///\param _os is a reference to the output stream.
1.118 + ///\param _os is a reference to the output stream.
1.119 + ///\param _pros If it is \c true, then the \c ostream referenced by \c _os
1.120 + ///will be explicitly deallocated by the destructor.
1.121 + ///By default it is <tt>std::cout</tt>
1.122 + DefaultGraphToEpsTraits(const G &_g,std::ostream& _os=std::cout,
1.123 + bool _pros=false) :
1.124 + g(_g), os(_os),
1.125 + _coords(xy<double>(1,1)), _nodeSizes(1.0),
1.126 + _nodeColors(Color(1,1,1)), _edgeColors(Color(0,0,0)),
1.127 + _edgeWidths(1), _edgeWidthScale(0.3),
1.128 + _nodeScale(1.0), _xBorder(10), _yBorder(10), _scale(1.0),
1.129 + _nodeBorderQuotient(.1),
1.130 + _drawArrows(false), _arrowLength(1), _arrowWidth(0.3),
1.131 + _showNodes(true), _showEdges(true),
1.132 + _enableParallel(false), _parEdgeDist(1),
1.133 + _showNodeText(false), _nodeTexts(false), _nodeTextSize(1),
1.134 + _undir(false),
1.135 + _pleaseRemoveOsStream(_pros) {}
1.136 +};
1.137 +
1.138 +///Helper class to implement the named parameters of \ref graphToEps()
1.139 +
1.140 +///Helper class to implement the named parameters of \ref graphToEps()
1.141 +///\todo Is 'helper class' a good name for this?
1.142 +///
1.143 +template<class T> class GraphToEps : public T
1.144 +{
1.145 + typedef typename T::Graph Graph;
1.146 + typedef typename Graph::Node Node;
1.147 + typedef typename Graph::NodeIt NodeIt;
1.148 + typedef typename Graph::Edge Edge;
1.149 + typedef typename Graph::EdgeIt EdgeIt;
1.150 + typedef typename Graph::InEdgeIt InEdgeIt;
1.151 + typedef typename Graph::OutEdgeIt OutEdgeIt;
1.152 +
1.153 + bool dontPrint;
1.154 +
1.155 + class edgeLess {
1.156 + const Graph &g;
1.157 + public:
1.158 + edgeLess(const Graph &_g) : g(_g) {}
1.159 + bool operator()(Edge a,Edge b) const
1.160 + {
1.161 + Node ai=min(g.source(a),g.target(a));
1.162 + Node aa=max(g.source(a),g.target(a));
1.163 + Node bi=min(g.source(b),g.target(b));
1.164 + Node ba=max(g.source(b),g.target(b));
1.165 + return ai<bi ||
1.166 + (ai==bi && (aa < ba ||
1.167 + (aa==ba && ai==g.source(a) && bi==g.target(b))));
1.168 + }
1.169 + };
1.170 + bool isParallel(Edge e,Edge f) const
1.171 + {
1.172 + return (g.source(e)==g.source(f)&&g.target(e)==g.target(f))||
1.173 + (g.source(e)==g.target(f)&&g.target(e)==g.source(f));
1.174 + }
1.175 + static xy<double> rot(xy<double> v)
1.176 + {
1.177 + return xy<double>(v.y,-v.x);
1.178 + }
1.179 + template<class xy>
1.180 + static std::string psOut(const xy &p)
1.181 + {
1.182 + std::ostringstream os;
1.183 + os << p.x << ' ' << p.y;
1.184 + return os.str();
1.185 + }
1.186 +
1.187 +public:
1.188 + GraphToEps(const T &t) : T(t), dontPrint(false) {};
1.189 +
1.190 + template<class X> struct CoordsTraits : public T {
1.191 + const X &_coords;
1.192 + CoordsTraits(const T &t,const X &x) : T(t), _coords(x) {}
1.193 + };
1.194 + ///Sets the map of the node coordinates
1.195 +
1.196 + ///Sets the map of the node coordinates.
1.197 + ///\param x must be a node map with xy<double> or xy<int> values.
1.198 + template<class X> GraphToEps<CoordsTraits<X> > coords(const X &x) {
1.199 + dontPrint=true;
1.200 + return GraphToEps<CoordsTraits<X> >(CoordsTraits<X>(*this,x));
1.201 + }
1.202 + template<class X> struct NodeSizesTraits : public T {
1.203 + const X &_nodeSizes;
1.204 + NodeSizesTraits(const T &t,const X &x) : T(t), _nodeSizes(x) {}
1.205 + };
1.206 + ///Sets the map of the node sizes
1.207 +
1.208 + ///Sets the map of the node sizes
1.209 + ///\param x must be a node map with \c double (or convertible) values.
1.210 + template<class X> GraphToEps<NodeSizesTraits<X> > nodeSizes(const X &x)
1.211 + {
1.212 + dontPrint=true;
1.213 + return GraphToEps<NodeSizesTraits<X> >(NodeSizesTraits<X>(*this,x));
1.214 + }
1.215 + template<class X> struct NodeTextsTraits : public T {
1.216 + const X &_nodeTexts;
1.217 + NodeTextsTraits(const T &t,const X &x) : T(t), _nodeTexts(x) {}
1.218 + };
1.219 + ///Sets the text printed on the nodes
1.220 +
1.221 + ///Sets the text printed on the nodes
1.222 + ///\param x must be a node map with type that can be pushed to a standard
1.223 + ///ostream.
1.224 + template<class X> GraphToEps<NodeTextsTraits<X> > nodeTexts(const X &x)
1.225 + {
1.226 + dontPrint=true;
1.227 + _showNodeText=true;
1.228 + return GraphToEps<NodeTextsTraits<X> >(NodeTextsTraits<X>(*this,x));
1.229 + }
1.230 + template<class X> struct EdgeWidthsTraits : public T {
1.231 + const X &_edgeWidths;
1.232 + EdgeWidthsTraits(const T &t,const X &x) : T(t), _edgeWidths(x) {}
1.233 + };
1.234 + ///Sets the map of the edge widths
1.235 +
1.236 + ///Sets the map of the edge widths
1.237 + ///\param x must be a edge map with \c double (or convertible) values.
1.238 + template<class X> GraphToEps<EdgeWidthsTraits<X> > edgeWidths(const X &x)
1.239 + {
1.240 + dontPrint=true;
1.241 + return GraphToEps<EdgeWidthsTraits<X> >(EdgeWidthsTraits<X>(*this,x));
1.242 + }
1.243 +
1.244 + template<class X> struct NodeColorsTraits : public T {
1.245 + const X &_nodeColors;
1.246 + NodeColorsTraits(const T &t,const X &x) : T(t), _nodeColors(x) {}
1.247 + };
1.248 + ///Sets the map of the node colors
1.249 +
1.250 + ///Sets the map of the node colors
1.251 + ///\param x must be a node map with \ref Color values.
1.252 + template<class X> GraphToEps<NodeColorsTraits<X> >
1.253 + nodeColors(const X &x)
1.254 + {
1.255 + dontPrint=true;
1.256 + return GraphToEps<NodeColorsTraits<X> >(NodeColorsTraits<X>(*this,x));
1.257 + }
1.258 + template<class X> struct EdgeColorsTraits : public T {
1.259 + const X &_edgeColors;
1.260 + EdgeColorsTraits(const T &t,const X &x) : T(t), _edgeColors(x) {}
1.261 + };
1.262 + ///Sets the map of the edge colors
1.263 +
1.264 + ///Sets the map of the edge colors
1.265 + ///\param x must be a edge map with \ref Color values.
1.266 + template<class X> GraphToEps<EdgeColorsTraits<X> >
1.267 + edgeColors(const X &x)
1.268 + {
1.269 + dontPrint=true;
1.270 + return GraphToEps<EdgeColorsTraits<X> >(EdgeColorsTraits<X>(*this,x));
1.271 + }
1.272 + ///Sets a global scale factor for node sizes
1.273 +
1.274 + ///Sets a global scale factor for node sizes
1.275 + ///
1.276 + GraphToEps<T> &nodeScale(double d) {_nodeScale=d;return *this;}
1.277 + ///Sets a global scale factor for edge widths
1.278 +
1.279 + ///Sets a global scale factor for edge widths
1.280 + ///
1.281 + GraphToEps<T> &edgeWidthScale(double d) {_edgeWidthScale=d;return *this;}
1.282 + ///Sets a global scale factor for the whole picture
1.283 +
1.284 + ///Sets a global scale factor for the whole picture
1.285 + ///
1.286 + GraphToEps<T> &scale(double d) {_scale=d;return *this;}
1.287 + ///Sets the width of the border around the picture
1.288 +
1.289 + ///Sets the width of the border around the picture
1.290 + ///
1.291 + GraphToEps<T> &border(double b) {_xBorder=_yBorder=b;return *this;}
1.292 + ///Sets the width of the border around the picture
1.293 +
1.294 + ///Sets the width of the border around the picture
1.295 + ///
1.296 + GraphToEps<T> &border(double x, double y) {
1.297 + _xBorder=x;_yBorder=y;return *this;
1.298 + }
1.299 + ///Sets whether to draw arrows
1.300 +
1.301 + ///Sets whether to draw arrows
1.302 + ///
1.303 + GraphToEps<T> &drawArrows(bool b=true) {_drawArrows=b;return *this;}
1.304 + ///Sets the length of the arrowheads
1.305 +
1.306 + ///Sets the length of the arrowheads
1.307 + ///
1.308 + GraphToEps<T> &arrowLength(double d) {_arrowLength*=d;return *this;}
1.309 + ///Sets the width of the arrowheads
1.310 +
1.311 + ///Sets the width of the arrowheads
1.312 + ///
1.313 + GraphToEps<T> &arrowWidth(double d) {_arrowWidth*=d;return *this;}
1.314 +
1.315 + ///Enables parallel edges
1.316 +
1.317 + ///Enables parallel edges
1.318 + ///\todo Partially implemented
1.319 + GraphToEps<T> &enableParallel(bool b=true) {_enableParallel=b;return *this;}
1.320 +
1.321 + ///Sets the distance
1.322 +
1.323 + ///Sets the distance
1.324 + ///
1.325 + GraphToEps<T> &parEdgeDist(double d) {_parEdgeDist*=d;return *this;}
1.326 +
1.327 + ///Hides the edges
1.328 +
1.329 + ///Hides the edges
1.330 + ///
1.331 + GraphToEps<T> &hideEdges(bool b=true) {_showEdges=!b;return *this;}
1.332 + ///Hides the nodes
1.333 +
1.334 + ///Hides the nodes
1.335 + ///
1.336 + GraphToEps<T> &hideNodes(bool b=true) {_showNodes=!b;return *this;}
1.337 +
1.338 + ///Sets the size of the node texts
1.339 +
1.340 + ///Sets the size of the node texts
1.341 + ///
1.342 + GraphToEps<T> &nodeTextSize(double d) {_nodeTextSize=d;return *this;}
1.343 + ///Sets whether the the graph is undirected
1.344 +
1.345 + ///Sets whether the the graph is undirected
1.346 + ///
1.347 + GraphToEps<T> &undir(bool b=true) {_undir=b;return *this;}
1.348 + ///Sets whether the the graph is directed
1.349 +
1.350 + ///Sets whether the the graph is directed.
1.351 + ///Use it to show the undirected edges as a pair of directed ones.
1.352 + GraphToEps<T> &bidir(bool b=true) {_undir=!b;return *this;}
1.353 +
1.354 + ~GraphToEps()
1.355 + {
1.356 + if(dontPrint) return;
1.357 +
1.358 + os << "%!PS-Adobe-2.0 EPSF-2.0\n";
1.359 + //\todo: Chech whether the graph is empty.
1.360 + BoundingBox<double> bb;
1.361 + for(NodeIt n(g);n!=INVALID;++n) {
1.362 + double ns=_nodeSizes[n]*_nodeScale;
1.363 + xy<double> p(ns,ns);
1.364 + bb+=p+_coords[n];
1.365 + bb+=-p+_coords[n];
1.366 + }
1.367 + os << "%%BoundingBox: "
1.368 + << bb.left()* _scale-_xBorder << ' '
1.369 + << bb.bottom()*_scale-_yBorder << ' '
1.370 + << bb.right()* _scale+_xBorder << ' '
1.371 + << bb.top()* _scale+_yBorder << '\n';
1.372 + //x1 y1 x2 y2 x3 y3 cr cg cb w
1.373 + os << "/lb { setlinewidth setrgbcolor newpath moveto\n"
1.374 + << " 4 2 roll 1 index 1 index curveto stroke } bind def\n";
1.375 + os << "/l { setlinewidth setrgbcolor newpath moveto lineto stroke } bind def\n";
1.376 + os << "/c { newpath dup 3 index add 2 index moveto 0 360 arc closepath } bind def\n";
1.377 + // x y r cr cg cb
1.378 + os << "/n { setrgbcolor 2 index 2 index 2 index c fill\n"
1.379 + << " 0 0 0 setrgbcolor dup "
1.380 + << _nodeBorderQuotient << " mul setlinewidth "
1.381 + << 1+_nodeBorderQuotient/2 << " div c stroke\n"
1.382 + << " } bind def\n";
1.383 + os << "/arrl " << _arrowLength << " def\n";
1.384 + os << "/arrw " << _arrowWidth << " def\n";
1.385 + // l dx_norm dy_norm
1.386 + os << "/lrl { 2 index mul exch 2 index mul exch rlineto pop} bind def\n";
1.387 + //len w dx_norm dy_norm x1 y1 cr cg cb
1.388 + os << "/arr { setrgbcolor /y1 exch def /x1 exch def /dy exch def /dx exch def\n"
1.389 + << " /w exch def /len exch def\n"
1.390 + // << " 0.1 setlinewidth x1 y1 moveto dx len mul dy len mul rlineto stroke"
1.391 + << " newpath x1 dy w 2 div mul add y1 dx w 2 div mul sub moveto\n"
1.392 + << " len w sub arrl sub dx dy lrl\n"
1.393 + << " arrw dy dx neg lrl\n"
1.394 + << " dx arrl w add mul dy w 2 div arrw add mul sub\n"
1.395 + << " dy arrl w add mul dx w 2 div arrw add mul add rlineto\n"
1.396 + << " dx arrl w add mul neg dy w 2 div arrw add mul sub\n"
1.397 + << " dy arrl w add mul neg dx w 2 div arrw add mul add rlineto\n"
1.398 + << " arrw dy dx neg lrl\n"
1.399 + << " len w sub arrl sub neg dx dy lrl\n"
1.400 + << " closepath fill } bind def\n";
1.401 + os << "/cshow { 2 index 2 index moveto dup stringwidth pop\n"
1.402 + << " neg 2 div fosi .35 mul neg rmoveto show pop pop} def\n";
1.403 +
1.404 + os << "\ngsave\n";
1.405 + if(_scale!=1.0) os << _scale << " dup scale\n";
1.406 +
1.407 + os << "%Edges:\ngsave\n";
1.408 +
1.409 + if(_showEdges)
1.410 + if(_enableParallel) {
1.411 + std::vector<Edge> el;
1.412 + for(EdgeIt e(g);e!=INVALID;++e)
1.413 + if(!_undir||g.source(e)<g.target(e)) el.push_back(e);
1.414 + sort(el.begin(),el.end(),edgeLess(g));
1.415 +
1.416 + typename std::vector<Edge>::iterator j;
1.417 + for(typename std::vector<Edge>::iterator i=el.begin();i!=el.end();i=j) {
1.418 + for(j=i+1;j!=el.end()&&isParallel(*i,*j);++j) ;
1.419 +
1.420 + double sw=0;
1.421 + for(typename std::vector<Edge>::iterator e=i;e!=j;++e)
1.422 + sw+=_edgeWidths[*e]*_edgeWidthScale+_parEdgeDist;
1.423 + sw-=_parEdgeDist;
1.424 + sw/=-2.0;
1.425 + xy<double> d(_coords[g.target(*i)]-_coords[g.source(*i)]);
1.426 + double l=sqrt(d.normSquare());
1.427 + d/=l;
1.428 +
1.429 + for(typename std::vector<Edge>::iterator e=i;e!=j;++e) {
1.430 + sw+=_edgeWidths[*e]*_edgeWidthScale/2.0;
1.431 + xy<double> m(_coords[g.target(*e)]+_coords[g.source(*e)]);
1.432 + m=m/2.0+rot(d)*sw/.75;
1.433 + if(_drawArrows) {
1.434 + const int INERPOL_PREC=20;
1.435 + xy<double> s=_coords[g.source(*e)];
1.436 + xy<double> t=_coords[g.target(*e)];
1.437 + double rn=_nodeSizes[g.target(*e)]*_nodeScale;
1.438 + rn*=rn;
1.439 + Bezier3 bez(s,m,m,t);
1.440 + double t1=0,t2=1;
1.441 + for(int i=0;i<INERPOL_PREC;++i)
1.442 + if((bez((t1+t2)/2)-t).normSquare()>rn) t1=(t1+t2)/2;
1.443 + else t2=(t1+t2)/2;
1.444 + xy<double> apoint=bez((t1+t2)/2);
1.445 + rn = _nodeSizes[g.target(*e)]*_nodeScale+_arrowLength+
1.446 + _edgeWidths[*e]*_edgeWidthScale;
1.447 + rn*=rn;
1.448 + t1=0;t2=1;
1.449 + for(int i=0;i<INERPOL_PREC;++i)
1.450 + if((bez((t1+t2)/2)-t).normSquare()>rn) t1=(t1+t2)/2;
1.451 + else t2=(t1+t2)/2;
1.452 + xy<double> linend=bez((t1+t2)/2);
1.453 + bez=bez.before((t1+t2)/2);
1.454 + rn=_nodeSizes[g.source(*e)]*_nodeScale; rn*=rn;
1.455 + t1=0;t2=1;
1.456 + for(int i=0;i<INERPOL_PREC;++i)
1.457 + if((bez((t1+t2)/2)-s).normSquare()>rn) t2=(t1+t2)/2;
1.458 + else t1=(t1+t2)/2;
1.459 + bez=bez.after((t1+t2)/2);
1.460 + os << _edgeWidths[*e]*_edgeWidthScale << " setlinewidth "
1.461 + << _edgeColors[*e].getR() << ' '
1.462 + << _edgeColors[*e].getG() << ' '
1.463 + << _edgeColors[*e].getB() << " setrgbcolor newpath\n"
1.464 + << bez.p1.x << ' ' << bez.p1.y << " moveto\n"
1.465 + << bez.p2.x << ' ' << bez.p2.y << ' '
1.466 + << bez.p3.x << ' ' << bez.p3.y << ' '
1.467 + << bez.p4.x << ' ' << bez.p4.y << " curveto stroke\n";
1.468 + xy<double> dd(rot(linend-apoint));
1.469 + dd*=(_edgeWidths[*e]*_edgeWidthScale+_arrowWidth)/
1.470 + sqrt(dd.normSquare());
1.471 + os << "newpath " << psOut(apoint) << " moveto "
1.472 + << psOut(linend+dd) << " lineto "
1.473 + << psOut(linend-dd) << " lineto closepath fill\n";
1.474 + }
1.475 + else {
1.476 + os << _coords[g.source(*e)].x << ' '
1.477 + << _coords[g.source(*e)].y << ' '
1.478 + << m.x << ' ' << m.y << ' '
1.479 + << _coords[g.target(*e)].x << ' '
1.480 + << _coords[g.target(*e)].y << ' '
1.481 + << _edgeColors[*e].getR() << ' '
1.482 + << _edgeColors[*e].getG() << ' '
1.483 + << _edgeColors[*e].getB() << ' '
1.484 + << _edgeWidths[*e]*_edgeWidthScale << " lb\n";
1.485 + }
1.486 + sw+=_edgeWidths[*e]*_edgeWidthScale/2.0+_parEdgeDist;
1.487 + }
1.488 + }
1.489 + }
1.490 + else for(EdgeIt e(g);e!=INVALID;++e)
1.491 + if(!_undir||g.source(e)<g.target(e))
1.492 + if(_drawArrows) {
1.493 + xy<double> d(_coords[g.target(e)]-_coords[g.source(e)]);
1.494 + double l=sqrt(d.normSquare());
1.495 + d/=l;
1.496 + xy<double> x1(d*_nodeScale*_nodeSizes[g.source(e)]+
1.497 + _coords[g.source(e)]);
1.498 + os << l-(_nodeSizes[g.source(e)]+
1.499 + _nodeSizes[g.target(e)])*_nodeScale << ' '
1.500 + << _edgeWidths[e]*_edgeWidthScale << ' '
1.501 + << d.x << ' ' << d.y << ' '
1.502 + << x1.x << ' ' << x1.y << ' '
1.503 + << _edgeColors[e].getR() << ' '
1.504 + << _edgeColors[e].getG() << ' '
1.505 + << _edgeColors[e].getB() << " arr\n";
1.506 + }
1.507 + else os << _coords[g.source(e)].x << ' '
1.508 + << _coords[g.source(e)].y << ' '
1.509 + << _coords[g.target(e)].x << ' '
1.510 + << _coords[g.target(e)].y << ' '
1.511 + << _edgeColors[e].getR() << ' '
1.512 + << _edgeColors[e].getG() << ' '
1.513 + << _edgeColors[e].getB() << ' '
1.514 + << _edgeWidths[e]*_edgeWidthScale << " l\n";
1.515 + os << "grestore\n%Nodes:\ngsave\n";
1.516 + if(_showNodes)
1.517 + for(NodeIt n(g);n!=INVALID;++n)
1.518 + os << _coords[n].x << ' ' << _coords[n].y << ' '
1.519 + << _nodeSizes[n]*_nodeScale << ' '
1.520 + << _nodeColors[n].getR() << ' '
1.521 + << _nodeColors[n].getG() << ' '
1.522 + << _nodeColors[n].getB() << " n\n";
1.523 + if(_showNodeText) {
1.524 + os << "grestore\n%Node texts:\ngsave\n";
1.525 + os << "/fosi " << _nodeTextSize << " def\n";
1.526 + os << "(Helvetica) findfont fosi scalefont setfont\n";
1.527 + os << "0 0 0 setrgbcolor\n";
1.528 + for(NodeIt n(g);n!=INVALID;++n)
1.529 + os << _coords[n].x << ' ' << _coords[n].y
1.530 + << " (" << _nodeTexts[n] << ") cshow\n";
1.531 + }
1.532 + os << "grestore\ngrestore\n";
1.533 +
1.534 + //CleanUp:
1.535 + if(_pleaseRemoveOsStream) {delete &os;}
1.536 + }
1.537 +};
1.538 +
1.539 +
1.540 +///Generates an EPS file from a graph
1.541 +
1.542 +///\ingroup misc
1.543 +///Generates an EPS file from a graph.
1.544 +///\param g is a reference to the graph to be printed
1.545 +///\param os is a reference to the output stream.
1.546 +///By default it is <tt>std::cout</tt>
1.547 +///
1.548 +///This function also has a lot of \ref named-templ-param "named parameters",
1.549 +///they are declared as the members of class \ref GraphToEps. The following
1.550 +///example shows how to use these parameters.
1.551 +///\code
1.552 +/// graphToEps(g).scale(10).coords(coords)
1.553 +/// .nodeScale(2).nodeSizes(sizes)
1.554 +/// .edgeWidthScale(.4);
1.555 +///\endcode
1.556 +///\sa GraphToEps
1.557 +///\sa graphToEps(G &g, char *file_name)
1.558 +template<class G>
1.559 +GraphToEps<DefaultGraphToEpsTraits<G> >
1.560 +graphToEps(G &g, std::ostream& os=std::cout)
1.561 +{
1.562 + return
1.563 + GraphToEps<DefaultGraphToEpsTraits<G> >(DefaultGraphToEpsTraits<G>(g,os));
1.564 +}
1.565 +
1.566 +///Generates an EPS file from a graph
1.567 +
1.568 +//\ingroup misc
1.569 +///This function does the same as
1.570 +///\ref graphToEps(G &g,std::ostream& os)
1.571 +///but it writes its output into the file \c file_name
1.572 +///instead of a stream.
1.573 +///\sa graphToEps(G &g, std::ostream& os)
1.574 +template<class G>
1.575 +GraphToEps<DefaultGraphToEpsTraits<G> >
1.576 +graphToEps(G &g,char *file_name)
1.577 +{
1.578 + return GraphToEps<DefaultGraphToEpsTraits<G> >
1.579 + (DefaultGraphToEpsTraits<G>(g,*new std::ofstream(file_name),true));
1.580 +}
1.581 +
1.582 +//Generates an EPS file from a graph.
1.583 +//\param g is a reference to the graph to be printed
1.584 +//\param file_name is the output file_name.
1.585 +//
1.586 +//This function also has a lot of \ref named-templ-param "named parameters",
1.587 +//they are declared as the members of class \ref GraphToEps. The following
1.588 +//example shows how to use these parameters.
1.589 +//\code
1.590 +// graphToEps(g).scale(10).coords(coords)
1.591 +// .nodeScale(2).nodeSizes(sizes)
1.592 +// .edgeWidthScale(.4);
1.593 +//\endcode
1.594 +//\sa GraphToEps
1.595 +//\todo Avoid duplicated documentation
1.596 +//\bug Exception handling is missing? (Or we can just ignore it?)
1.597 +
1.598 +} //END OF NAMESPACE LEMON
1.599 +
1.600 +#endif // LEMON_GRAPH_TO_EPS_H