lemon/graph_to_eps.h
author deba
Wed, 01 Mar 2006 10:25:30 +0000
changeset 1991 d7442141d9ef
parent 1971 9a59a6cacfd9
child 1993 2115143eceea
permissions -rw-r--r--
The graph adadptors can be alteration observed.
In most cases it uses the adapted graph alteration notifiers.
Only special case is now the UndirGraphAdaptor, where
we have to proxy the signals from the graph.

The SubBidirGraphAdaptor is removed, because it doest not
gives more feature than the EdgeSubGraphAdaptor<UndirGraphAdaptor<Graph>>.

The ResGraphAdaptor is based on this composition.
     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 #ifndef LEMON_GRAPH_TO_EPS_H
    20 #define LEMON_GRAPH_TO_EPS_H
    21 
    22 #include <sys/time.h>
    23 
    24 #include<iostream>
    25 #include<fstream>
    26 #include<sstream>
    27 #include<algorithm>
    28 #include<vector>
    29 
    30 #include <ctime>
    31 #include <cmath>
    32 
    33 #include<lemon/invalid.h>
    34 #include<lemon/xy.h>
    35 #include<lemon/maps.h>
    36 #include<lemon/color.h>
    37 #include<lemon/bezier.h>
    38 
    39 
    40 ///\ingroup io_group
    41 ///\file
    42 ///\brief Simple graph drawer
    43 ///
    44 ///\author Alpar Juttner
    45 
    46 namespace lemon {
    47 
    48 template<class MT>
    49 class _NegY {
    50 public:
    51   typedef typename MT::Key Key;
    52   typedef typename MT::Value Value;
    53   const MT &map;
    54   int yscale;
    55   _NegY(const MT &m,bool b) : map(m), yscale(1-b*2) {}
    56   Value operator[](Key n) { return Value(map[n].x,map[n].y*yscale);}
    57 };
    58 
    59 ///Default traits class of \ref GraphToEps
    60 
    61 ///Default traits class of \ref GraphToEps
    62 ///
    63 ///\c G is the type of the underlying graph.
    64 template<class G>
    65 struct DefaultGraphToEpsTraits
    66 {
    67   typedef G Graph;
    68   typedef typename Graph::Node Node;
    69   typedef typename Graph::NodeIt NodeIt;
    70   typedef typename Graph::Edge Edge;
    71   typedef typename Graph::EdgeIt EdgeIt;
    72   typedef typename Graph::InEdgeIt InEdgeIt;
    73   typedef typename Graph::OutEdgeIt OutEdgeIt;
    74   
    75 
    76   const Graph &g;
    77 
    78   std::ostream& os;
    79   
    80   typedef ConstMap<typename Graph::Node,xy<double> > CoordsMapType;
    81   CoordsMapType _coords;
    82   ConstMap<typename Graph::Node,double > _nodeSizes;
    83   ConstMap<typename Graph::Node,int > _nodeShapes;
    84 
    85   ConstMap<typename Graph::Node,Color > _nodeColors;
    86   ConstMap<typename Graph::Edge,Color > _edgeColors;
    87 
    88   ConstMap<typename Graph::Edge,double > _edgeWidths;
    89 
    90   double _edgeWidthScale;
    91   
    92   double _nodeScale;
    93   double _xBorder, _yBorder;
    94   double _scale;
    95   double _nodeBorderQuotient;
    96   
    97   bool _drawArrows;
    98   double _arrowLength, _arrowWidth;
    99   
   100   bool _showNodes, _showEdges;
   101 
   102   bool _enableParallel;
   103   double _parEdgeDist;
   104 
   105   bool _showNodeText;
   106   ConstMap<typename Graph::Node,bool > _nodeTexts;  
   107   double _nodeTextSize;
   108 
   109   bool _showNodePsText;
   110   ConstMap<typename Graph::Node,bool > _nodePsTexts;  
   111   char *_nodePsTextsPreamble;
   112   
   113   bool _undirected;
   114 
   115   bool _pleaseRemoveOsStream;
   116 
   117   bool _scaleToA4;
   118 
   119   std::string _title;
   120   std::string _copyright;
   121 
   122   enum NodeTextColorType 
   123     { DIST_COL=0, DIST_BW=1, CUST_COL=2, SAME_COL=3 } _nodeTextColorType;
   124   ConstMap<typename Graph::Node,Color > _nodeTextColors;
   125 
   126   bool _autoNodeScale;
   127   bool _autoEdgeWidthScale;
   128 
   129   bool _negY;
   130   ///Constructor
   131 
   132   ///Constructor
   133   ///\param _g is a reference to the graph to be printed
   134   ///\param _os is a reference to the output stream.
   135   ///\param _os is a reference to the output stream.
   136   ///\param _pros If it is \c true, then the \c ostream referenced by \c _os
   137   ///will be explicitly deallocated by the destructor.
   138   ///By default it is <tt>std::cout</tt>
   139   DefaultGraphToEpsTraits(const G &_g,std::ostream& _os=std::cout,
   140 			  bool _pros=false) :
   141     g(_g), os(_os),
   142     _coords(xy<double>(1,1)), _nodeSizes(1.0), _nodeShapes(0),
   143     _nodeColors(Color(1,1,1)), _edgeColors(Color(0,0,0)),
   144     _edgeWidths(1), _edgeWidthScale(0.3),
   145     _nodeScale(1.0), _xBorder(10), _yBorder(10), _scale(1.0),
   146     _nodeBorderQuotient(.1),
   147     _drawArrows(false), _arrowLength(1), _arrowWidth(0.3),
   148     _showNodes(true), _showEdges(true),
   149     _enableParallel(false), _parEdgeDist(1),
   150     _showNodeText(false), _nodeTexts(false), _nodeTextSize(1),
   151     _showNodePsText(false), _nodePsTexts(false), _nodePsTextsPreamble(0),
   152     _undirected(false),
   153     _pleaseRemoveOsStream(_pros), _scaleToA4(false),
   154     _nodeTextColorType(SAME_COL), _nodeTextColors(Color(0,0,0)),
   155     _autoNodeScale(false),
   156     _autoEdgeWidthScale(false),
   157     _negY(false)
   158   {}
   159 };
   160 
   161 ///Helper class to implement the named parameters of \ref graphToEps()
   162 
   163 ///Helper class to implement the named parameters of \ref graphToEps()
   164 ///\todo Is 'helper class' a good name for this?
   165 ///
   166 ///\todo Follow PostScript's DSC.
   167 /// Use own dictionary.
   168 ///\todo Useful new features.
   169 /// - Linestyles: dotted, dashed etc.
   170 /// - A second color and percent value for the lines.
   171 template<class T> class GraphToEps : public T 
   172 {
   173   // Can't believe it is required by the C++ standard
   174   using T::g;
   175   using T::os;
   176 
   177   using T::_coords;
   178   using T::_nodeSizes;
   179   using T::_nodeShapes;
   180   using T::_nodeColors;
   181   using T::_edgeColors;
   182   using T::_edgeWidths;
   183 
   184   using T::_edgeWidthScale;
   185   using T::_nodeScale;
   186   using T::_xBorder;
   187   using T::_yBorder;
   188   using T::_scale;
   189   using T::_nodeBorderQuotient;
   190   
   191   using T::_drawArrows;
   192   using T::_arrowLength;
   193   using T::_arrowWidth;
   194   
   195   using T::_showNodes;
   196   using T::_showEdges;
   197 
   198   using T::_enableParallel;
   199   using T::_parEdgeDist;
   200 
   201   using T::_showNodeText;
   202   using T::_nodeTexts;  
   203   using T::_nodeTextSize;
   204 
   205   using T::_showNodePsText;
   206   using T::_nodePsTexts;  
   207   using T::_nodePsTextsPreamble;
   208   
   209   using T::_undirected;
   210 
   211   using T::_pleaseRemoveOsStream;
   212 
   213   using T::_scaleToA4;
   214 
   215   using T::_title;
   216   using T::_copyright;
   217 
   218   using T::NodeTextColorType;
   219   using T::CUST_COL;
   220   using T::DIST_COL;
   221   using T::DIST_BW;
   222   using T::_nodeTextColorType;
   223   using T::_nodeTextColors;
   224 
   225   using T::_autoNodeScale;
   226   using T::_autoEdgeWidthScale;
   227 
   228   using T::_negY;
   229 
   230   // dradnats ++C eht yb deriuqer si ti eveileb t'naC
   231 
   232   typedef typename T::Graph Graph;
   233   typedef typename Graph::Node Node;
   234   typedef typename Graph::NodeIt NodeIt;
   235   typedef typename Graph::Edge Edge;
   236   typedef typename Graph::EdgeIt EdgeIt;
   237   typedef typename Graph::InEdgeIt InEdgeIt;
   238   typedef typename Graph::OutEdgeIt OutEdgeIt;
   239 
   240   static const int INTERPOL_PREC;
   241   static const double A4HEIGHT;
   242   static const double A4WIDTH;
   243   static const double A4BORDER;
   244 
   245   bool dontPrint;
   246 
   247 public:
   248   ///Node shapes
   249 
   250   ///Node shapes
   251   ///
   252   enum NodeShapes { 
   253     /// = 0
   254     ///\image html nodeshape_0.png
   255     ///\image latex nodeshape_0.eps "CIRCLE shape (0)" width=2cm
   256     CIRCLE=0, 
   257     /// = 1
   258     ///\image html nodeshape_1.png
   259     ///\image latex nodeshape_1.eps "SQUARE shape (1)" width=2cm
   260     ///
   261     SQUARE=1, 
   262     /// = 2
   263     ///\image html nodeshape_2.png
   264     ///\image latex nodeshape_2.eps "DIAMOND shape (2)" width=2cm
   265     ///
   266     DIAMOND=2,
   267     /// = 3
   268     ///\image html nodeshape_3.png
   269     ///\image latex nodeshape_2.eps "MALE shape (4)" width=2cm
   270     ///
   271     MALE=3,
   272     /// = 4
   273     ///\image html nodeshape_4.png
   274     ///\image latex nodeshape_2.eps "FEMALE shape (4)" width=2cm
   275     ///
   276     FEMALE=4
   277   };
   278 
   279 private:
   280   class edgeLess {
   281     const Graph &g;
   282   public:
   283     edgeLess(const Graph &_g) : g(_g) {}
   284     bool operator()(Edge a,Edge b) const 
   285     {
   286       Node ai=std::min(g.source(a),g.target(a));
   287       Node aa=std::max(g.source(a),g.target(a));
   288       Node bi=std::min(g.source(b),g.target(b));
   289       Node ba=std::max(g.source(b),g.target(b));
   290       return ai<bi ||
   291 	(ai==bi && (aa < ba || 
   292 		    (aa==ba && ai==g.source(a) && bi==g.target(b))));
   293     }
   294   };
   295   bool isParallel(Edge e,Edge f) const
   296   {
   297     return (g.source(e)==g.source(f)&&
   298 	    g.target(e)==g.target(f)) ||
   299       (g.source(e)==g.target(f)&&
   300        g.target(e)==g.source(f));
   301   }
   302   template<class TT>
   303   static std::string psOut(const xy<TT> &p) 
   304     {
   305       std::ostringstream os;	
   306       os << p.x << ' ' << p.y;
   307       return os.str();
   308     }
   309   static std::string psOut(const Color &c) 
   310     {
   311       std::ostringstream os;	
   312       os << c.red() << ' ' << c.green() << ' ' << c.blue();
   313       return os.str();
   314     }
   315   
   316 public:
   317   GraphToEps(const T &t) : T(t), dontPrint(false) {};
   318   
   319   template<class X> struct CoordsTraits : public T {
   320   typedef X CoordsMapType;
   321     const X &_coords;
   322     CoordsTraits(const T &t,const X &x) : T(t), _coords(x) {}
   323   };
   324   ///Sets the map of the node coordinates
   325 
   326   ///Sets the map of the node coordinates.
   327   ///\param x must be a node map with xy<double> or \ref xy "xy<int>" values. 
   328   template<class X> GraphToEps<CoordsTraits<X> > coords(const X &x) {
   329     dontPrint=true;
   330     return GraphToEps<CoordsTraits<X> >(CoordsTraits<X>(*this,x));
   331   }
   332   template<class X> struct NodeSizesTraits : public T {
   333     const X &_nodeSizes;
   334     NodeSizesTraits(const T &t,const X &x) : T(t), _nodeSizes(x) {}
   335   };
   336   ///Sets the map of the node sizes
   337 
   338   ///Sets the map of the node sizes
   339   ///\param x must be a node map with \c double (or convertible) values. 
   340   template<class X> GraphToEps<NodeSizesTraits<X> > nodeSizes(const X &x)
   341   {
   342     dontPrint=true;
   343     return GraphToEps<NodeSizesTraits<X> >(NodeSizesTraits<X>(*this,x));
   344   }
   345   template<class X> struct NodeShapesTraits : public T {
   346     const X &_nodeShapes;
   347     NodeShapesTraits(const T &t,const X &x) : T(t), _nodeShapes(x) {}
   348   };
   349   ///Sets the map of the node shapes
   350 
   351   ///Sets the map of the node shapes.
   352   ///The availabe shape values
   353   ///can be found in \ref NodeShapes "enum NodeShapes".
   354   ///\param x must be a node map with \c int (or convertible) values. 
   355   ///\sa NodeShapes
   356   template<class X> GraphToEps<NodeShapesTraits<X> > nodeShapes(const X &x)
   357   {
   358     dontPrint=true;
   359     return GraphToEps<NodeShapesTraits<X> >(NodeShapesTraits<X>(*this,x));
   360   }
   361   template<class X> struct NodeTextsTraits : public T {
   362     const X &_nodeTexts;
   363     NodeTextsTraits(const T &t,const X &x) : T(t), _nodeTexts(x) {}
   364   };
   365   ///Sets the text printed on the nodes
   366 
   367   ///Sets the text printed on the nodes
   368   ///\param x must be a node map with type that can be pushed to a standard
   369   ///ostream. 
   370   template<class X> GraphToEps<NodeTextsTraits<X> > nodeTexts(const X &x)
   371   {
   372     dontPrint=true;
   373     _showNodeText=true;
   374     return GraphToEps<NodeTextsTraits<X> >(NodeTextsTraits<X>(*this,x));
   375   }
   376   template<class X> struct NodePsTextsTraits : public T {
   377     const X &_nodePsTexts;
   378     NodePsTextsTraits(const T &t,const X &x) : T(t), _nodePsTexts(x) {}
   379   };
   380   ///Inserts a PostScript block to the nodes
   381 
   382   ///With this command it is possible to insert a verbatim PostScript
   383   ///block to the nodes.
   384   ///The PS current point will be moved to the centre of the node before
   385   ///the PostScript block inserted.
   386   ///
   387   ///Before and after the block a newline character is inserted so you
   388   ///don't have to bother with the separators.
   389   ///
   390   ///\param x must be a node map with type that can be pushed to a standard
   391   ///ostream.
   392   ///
   393   ///\sa nodePsTextsPreamble()
   394   ///\todo Offer the choise not to move to the centre but pass the coordinates
   395   ///to the Postscript block inserted.
   396   template<class X> GraphToEps<NodePsTextsTraits<X> > nodePsTexts(const X &x)
   397   {
   398     dontPrint=true;
   399     _showNodePsText=true;
   400     return GraphToEps<NodePsTextsTraits<X> >(NodePsTextsTraits<X>(*this,x));
   401   }
   402   template<class X> struct EdgeWidthsTraits : public T {
   403     const X &_edgeWidths;
   404     EdgeWidthsTraits(const T &t,const X &x) : T(t), _edgeWidths(x) {}
   405   };
   406   ///Sets the map of the edge widths
   407 
   408   ///Sets the map of the edge widths
   409   ///\param x must be a edge map with \c double (or convertible) values. 
   410   template<class X> GraphToEps<EdgeWidthsTraits<X> > edgeWidths(const X &x)
   411   {
   412     dontPrint=true;
   413     return GraphToEps<EdgeWidthsTraits<X> >(EdgeWidthsTraits<X>(*this,x));
   414   }
   415 
   416   template<class X> struct NodeColorsTraits : public T {
   417     const X &_nodeColors;
   418     NodeColorsTraits(const T &t,const X &x) : T(t), _nodeColors(x) {}
   419   };
   420   ///Sets the map of the node colors
   421 
   422   ///Sets the map of the node colors
   423   ///\param x must be a node map with \ref Color values.
   424   ///
   425   ///\sa ColorSet
   426   template<class X> GraphToEps<NodeColorsTraits<X> >
   427   nodeColors(const X &x)
   428   {
   429     dontPrint=true;
   430     return GraphToEps<NodeColorsTraits<X> >(NodeColorsTraits<X>(*this,x));
   431   }
   432   template<class X> struct NodeTextColorsTraits : public T {
   433     const X &_nodeTextColors;
   434     NodeTextColorsTraits(const T &t,const X &x) : T(t), _nodeTextColors(x) {}
   435   };
   436   ///Sets the map of the node text colors
   437 
   438   ///Sets the map of the node text colors
   439   ///\param x must be a node map with \ref Color values. 
   440   ///
   441   ///\sa ColorSet
   442   template<class X> GraphToEps<NodeTextColorsTraits<X> >
   443   nodeTextColors(const X &x)
   444   {
   445     dontPrint=true;
   446     _nodeTextColorType=CUST_COL;
   447     return GraphToEps<NodeTextColorsTraits<X> >
   448       (NodeTextColorsTraits<X>(*this,x));
   449   }
   450   template<class X> struct EdgeColorsTraits : public T {
   451     const X &_edgeColors;
   452     EdgeColorsTraits(const T &t,const X &x) : T(t), _edgeColors(x) {}
   453   };
   454   ///Sets the map of the edge colors
   455 
   456   ///Sets the map of the edge colors
   457   ///\param x must be a edge map with \ref Color values. 
   458   ///
   459   ///\sa ColorSet
   460   template<class X> GraphToEps<EdgeColorsTraits<X> >
   461   edgeColors(const X &x)
   462   {
   463     dontPrint=true;
   464     return GraphToEps<EdgeColorsTraits<X> >(EdgeColorsTraits<X>(*this,x));
   465   }
   466   ///Sets a global scale factor for node sizes
   467 
   468   ///Sets a global scale factor for node sizes.
   469   /// 
   470   /// If nodeSizes() is not given, this function simply sets the node
   471   /// sizes to \c d.  If nodeSizes() is given, but
   472   /// autoNodeScale() is not, then the node size given by
   473   /// nodeSizes() will be multiplied by the value \c d.
   474   /// If both nodeSizes() and autoNodeScale() are used, then the
   475   /// node sizes will be scaled in such a way that the greatest size will be
   476   /// equal to \c d.
   477   GraphToEps<T> &nodeScale(double d) {_nodeScale=d;return *this;}
   478   ///Turns on/off the automatic node width scaling.
   479 
   480   ///Turns on/off the automatic node width scaling.
   481   ///
   482   ///\sa nodeScale()
   483   ///
   484   GraphToEps<T> &autoNodeScale(bool b=true) {
   485     _autoNodeScale=b;return *this;
   486   }
   487 
   488   ///Negates the Y coordinates.
   489 
   490   ///Negates the Y coordinates.
   491   ///
   492   ///\todo More docs.
   493   ///
   494   GraphToEps<T> &negateY(bool b=true) {
   495     _negY=b;return *this;
   496   }
   497 
   498   ///Sets a global scale factor for edge widths
   499 
   500   /// Sets a global scale factor for edge widths.
   501   ///
   502   /// If edgeWidths() is not given, this function simply sets the edge
   503   /// widths to \c d.  If edgeWidths() is given, but
   504   /// autoEdgeWidthScale() is not, then the edge withs given by
   505   /// edgeWidths() will be multiplied by the value \c d.
   506   /// If both edgeWidths() and autoEdgeWidthScale() are used, then the
   507   /// edge withs will be scaled in such a way that the greatest width will be
   508   /// equal to \c d.
   509   GraphToEps<T> &edgeWidthScale(double d) {_edgeWidthScale=d;return *this;}
   510   ///Turns on/off the automatic edge width scaling.
   511 
   512   ///Turns on/off the automatic edge width scaling.
   513   ///
   514   ///\sa edgeWidthScale()
   515   ///
   516   GraphToEps<T> &autoEdgeWidthScale(bool b=true) {
   517     _autoEdgeWidthScale=b;return *this;
   518   }
   519   ///Sets a global scale factor for the whole picture
   520 
   521   ///Sets a global scale factor for the whole picture
   522   ///
   523 
   524   GraphToEps<T> &scale(double d) {_scale=d;return *this;}
   525   ///Sets the width of the border around the picture
   526 
   527   ///Sets the width of the border around the picture
   528   ///
   529   GraphToEps<T> &border(double b) {_xBorder=_yBorder=b;return *this;}
   530   ///Sets the width of the border around the picture
   531 
   532   ///Sets the width of the border around the picture
   533   ///
   534   GraphToEps<T> &border(double x, double y) {
   535     _xBorder=x;_yBorder=y;return *this;
   536   }
   537   ///Sets whether to draw arrows
   538 
   539   ///Sets whether to draw arrows
   540   ///
   541   GraphToEps<T> &drawArrows(bool b=true) {_drawArrows=b;return *this;}
   542   ///Sets the length of the arrowheads
   543 
   544   ///Sets the length of the arrowheads
   545   ///
   546   GraphToEps<T> &arrowLength(double d) {_arrowLength*=d;return *this;}
   547   ///Sets the width of the arrowheads
   548 
   549   ///Sets the width of the arrowheads
   550   ///
   551   GraphToEps<T> &arrowWidth(double d) {_arrowWidth*=d;return *this;}
   552   
   553   ///Scales the drawing to fit to A4 page
   554 
   555   ///Scales the drawing to fit to A4 page
   556   ///
   557   GraphToEps<T> &scaleToA4() {_scaleToA4=true;return *this;}
   558   
   559   ///Enables parallel edges
   560 
   561   ///Enables parallel edges
   562   GraphToEps<T> &enableParallel(bool b=true) {_enableParallel=b;return *this;}
   563   
   564   ///Sets the distance 
   565   
   566   ///Sets the distance 
   567   ///
   568   GraphToEps<T> &parEdgeDist(double d) {_parEdgeDist*=d;return *this;}
   569   
   570   ///Hides the edges
   571   
   572   ///Hides the edges
   573   ///
   574   GraphToEps<T> &hideEdges(bool b=true) {_showEdges=!b;return *this;}
   575   ///Hides the nodes
   576   
   577   ///Hides the nodes
   578   ///
   579   GraphToEps<T> &hideNodes(bool b=true) {_showNodes=!b;return *this;}
   580   
   581   ///Sets the size of the node texts
   582   
   583   ///Sets the size of the node texts
   584   ///
   585   GraphToEps<T> &nodeTextSize(double d) {_nodeTextSize=d;return *this;}
   586 
   587   ///Sets the color of the node texts to be different from the node color
   588 
   589   ///Sets the color of the node texts to be as different from the node color
   590   ///as it is possible
   591   ///
   592   GraphToEps<T> &distantColorNodeTexts()
   593   {_nodeTextColorType=DIST_COL;return *this;}
   594   ///Sets the color of the node texts to be black or white and always visible.
   595 
   596   ///Sets the color of the node texts to be black or white according to
   597   ///which is more 
   598   ///different from the node color
   599   ///
   600   GraphToEps<T> &distantBWNodeTexts()
   601   {_nodeTextColorType=DIST_BW;return *this;}
   602 
   603   ///Gives a preamble block for node Postscript block.
   604   
   605   ///Gives a preamble block for node Postscript block.
   606   ///
   607   ///\sa nodePsTexts()
   608   GraphToEps<T> & nodePsTextsPreamble(const char *str) {
   609     _nodePsTextsPreamble=str ;return *this;
   610   }
   611   ///Sets whether the the graph is undirected
   612 
   613   ///Sets whether the the graph is undirected
   614   ///
   615   GraphToEps<T> &undirected(bool b=true) {_undirected=b;return *this;}
   616 
   617   ///Sets whether the the graph is directed
   618 
   619   ///Sets whether the the graph is directed.
   620   ///Use it to show the undirected edges as a pair of directed ones.
   621   GraphToEps<T> &bidir(bool b=true) {_undirected=!b;return *this;}
   622 
   623   ///Sets the title.
   624 
   625   ///Sets the title of the generated image,
   626   ///namely it inserts a <tt>%%Title:</tt> DSC field to the header of
   627   ///the EPS file.
   628   GraphToEps<T> &title(const std::string &t) {_title=t;return *this;}
   629   ///Sets the copyright statement.
   630 
   631   ///Sets the copyright statement of the generated image,
   632   ///namely it inserts a <tt>%%Copyright:</tt> DSC field to the header of
   633   ///the EPS file.
   634   ///\todo Multiline copyright notice could be supported.
   635   GraphToEps<T> &copyright(const std::string &t) {_copyright=t;return *this;}
   636 
   637 protected:
   638   bool isInsideNode(xy<double> p, double r,int t) 
   639   {
   640     switch(t) {
   641     case CIRCLE:
   642     case MALE:
   643     case FEMALE:
   644       return p.normSquare()<=r*r;
   645     case SQUARE:
   646       return p.x<=r&&p.x>=-r&&p.y<=r&&p.y>=-r;
   647     case DIAMOND:
   648       return p.x+p.y<=r && p.x-p.y<=r && -p.x+p.y<=r && -p.x-p.y<=r;
   649     }
   650     return false;
   651   }
   652 
   653 public:
   654   ~GraphToEps() { }
   655   
   656   ///Draws the graph.
   657 
   658   ///Like other functions using
   659   ///\ref named-templ-func-param "named template parameters",
   660   ///this function calles the algorithm itself, i.e. in this case
   661   ///it draws the graph.
   662   void run() {
   663     if(dontPrint) return;
   664     
   665     _NegY<typename T::CoordsMapType> mycoords(_coords,_negY);
   666 
   667     os << "%!PS-Adobe-2.0 EPSF-2.0\n";
   668     if(_title.size()>0) os << "%%Title: " << _title << '\n';
   669      if(_copyright.size()>0) os << "%%Copyright: " << _copyright << '\n';
   670 //        << "%%Copyright: XXXX\n"
   671     os << "%%Creator: LEMON, graphToEps()\n";
   672     
   673     {
   674       char cbuf[50];
   675       timeval tv;
   676       gettimeofday(&tv, 0);
   677       ctime_r(&tv.tv_sec,cbuf);
   678       os << "%%CreationDate: " << cbuf;
   679     }
   680 
   681     if (_autoEdgeWidthScale) {
   682       double max_w=0;
   683       for(EdgeIt e(g);e!=INVALID;++e)
   684 	max_w=std::max(double(_edgeWidths[e]),max_w);
   685       ///\todo better 'epsilon' would be nice here.
   686       if(max_w>1e-9) {
   687 	_edgeWidthScale/=max_w;
   688       }
   689     }
   690 
   691     if (_autoNodeScale) {
   692       double max_s=0;
   693       for(NodeIt n(g);n!=INVALID;++n)
   694 	max_s=std::max(double(_nodeSizes[n]),max_s);
   695       ///\todo better 'epsilon' would be nice here.
   696       if(max_s>1e-9) {
   697 	_nodeScale/=max_s;
   698       }
   699     }
   700 
   701 
   702     BoundingBox<double> bb;
   703     ///\bug: Chech whether the graph is empty.
   704     for(NodeIt n(g);n!=INVALID;++n) {
   705       double ns=_nodeSizes[n]*_nodeScale;
   706       xy<double> p(ns,ns);
   707       switch(_nodeShapes[n]) {
   708       case CIRCLE:
   709       case SQUARE:
   710       case DIAMOND:
   711 	bb.add(p+mycoords[n]);
   712 	bb.add(-p+mycoords[n]);
   713 	break;
   714       case MALE:
   715 	bb.add(-p+mycoords[n]);
   716 	bb.add(xy<double>(1.5*ns,1.5*std::sqrt(3.0)*ns)+mycoords[n]);
   717 	break;
   718       case FEMALE:
   719 	bb.add(p+mycoords[n]);
   720 	bb.add(xy<double>(-ns,-3.01*ns)+mycoords[n]);
   721 	break;
   722       }
   723     }
   724     if (bb.empty()) {
   725       bb = BoundingBox<double>(xy<double>(0,0));
   726     }
   727     
   728     if(_scaleToA4)
   729       os <<"%%BoundingBox: 0 0 596 842\n%%DocumentPaperSizes: a4\n";
   730     else {
   731       //Rescale so that BoundingBox won't be neither to big nor too small.
   732       while(bb.height()*_scale>1000||bb.width()*_scale>1000) _scale/=10;
   733       while(bb.height()*_scale<100||bb.width()*_scale<100) _scale*=10;
   734     
   735       os << "%%BoundingBox: "
   736 	 << int(floor(bb.left()   * _scale - _xBorder)) << ' '
   737 	 << int(floor(bb.bottom() * _scale - _yBorder)) << ' '
   738 	 << int(ceil(bb.right()  * _scale + _xBorder)) << ' '
   739 	 << int(ceil(bb.top()    * _scale + _yBorder)) << '\n';
   740     }
   741     
   742     os << "%%EndComments\n";
   743     
   744     //x1 y1 x2 y2 x3 y3 cr cg cb w
   745     os << "/lb { setlinewidth setrgbcolor newpath moveto\n"
   746        << "      4 2 roll 1 index 1 index curveto stroke } bind def\n";
   747     os << "/l { setlinewidth setrgbcolor newpath moveto lineto stroke } bind def\n";
   748     //x y r
   749     os << "/c { newpath dup 3 index add 2 index moveto 0 360 arc closepath } bind def\n";
   750     //x y r
   751     os << "/sq { newpath 2 index 1 index add 2 index 2 index add moveto\n"
   752        << "      2 index 1 index sub 2 index 2 index add lineto\n"
   753        << "      2 index 1 index sub 2 index 2 index sub lineto\n"
   754        << "      2 index 1 index add 2 index 2 index sub lineto\n"
   755        << "      closepath pop pop pop} bind def\n";
   756     //x y r
   757     os << "/di { newpath 2 index 1 index add 2 index moveto\n"
   758        << "      2 index             2 index 2 index add lineto\n"
   759        << "      2 index 1 index sub 2 index             lineto\n"
   760        << "      2 index             2 index 2 index sub lineto\n"
   761        << "      closepath pop pop pop} bind def\n";
   762     // x y r cr cg cb
   763     os << "/nc { 0 0 0 setrgbcolor 5 index 5 index 5 index c fill\n"
   764        << "     setrgbcolor " << 1+_nodeBorderQuotient << " div c fill\n"
   765        << "   } bind def\n";
   766     os << "/nsq { 0 0 0 setrgbcolor 5 index 5 index 5 index sq fill\n"
   767        << "     setrgbcolor " << 1+_nodeBorderQuotient << " div sq fill\n"
   768        << "   } bind def\n";
   769     os << "/ndi { 0 0 0 setrgbcolor 5 index 5 index 5 index di fill\n"
   770        << "     setrgbcolor " << 1+_nodeBorderQuotient << " div di fill\n"
   771        << "   } bind def\n";
   772     os << "/nfemale { 0 0 0 setrgbcolor 3 index "
   773        << _nodeBorderQuotient/(1+_nodeBorderQuotient)
   774        << " 1.5 mul mul setlinewidth\n"
   775        << "  newpath 5 index 5 index moveto "
   776        << "5 index 5 index 5 index 3.01 mul sub\n"
   777        << "  lineto 5 index 4 index .7 mul sub 5 index 5 index 2.2 mul sub moveto\n"
   778        << "  5 index 4 index .7 mul add 5 index 5 index 2.2 mul sub lineto stroke\n"
   779        << "  5 index 5 index 5 index c fill\n"
   780        << "  setrgbcolor " << 1+_nodeBorderQuotient << " div c fill\n"
   781        << "  } bind def\n";
   782     os << "/nmale {\n"
   783        << "  0 0 0 setrgbcolor 3 index "
   784        << _nodeBorderQuotient/(1+_nodeBorderQuotient)
   785        <<" 1.5 mul mul setlinewidth\n"
   786        << "  newpath 5 index 5 index moveto\n"
   787        << "  5 index 4 index 1 mul 1.5 mul add\n"
   788        << "  5 index 5 index 3 sqrt 1.5 mul mul add\n"
   789        << "  1 index 1 index lineto\n"
   790        << "  1 index 1 index 7 index sub moveto\n"
   791        << "  1 index 1 index lineto\n"
   792        << "  exch 5 index 3 sqrt .5 mul mul sub exch 5 index .5 mul sub lineto\n"
   793        << "  stroke\n"
   794        << "  5 index 5 index 5 index c fill\n"
   795        << "  setrgbcolor " << 1+_nodeBorderQuotient << " div c fill\n"
   796        << "  } bind def\n";
   797     
   798 
   799     os << "/arrl " << _arrowLength << " def\n";
   800     os << "/arrw " << _arrowWidth << " def\n";
   801     // l dx_norm dy_norm
   802     os << "/lrl { 2 index mul exch 2 index mul exch rlineto pop} bind def\n";
   803     //len w dx_norm dy_norm x1 y1 cr cg cb
   804     os << "/arr { setrgbcolor /y1 exch def /x1 exch def /dy exch def /dx exch def\n"
   805        << "       /w exch def /len exch def\n"
   806       //	 << "       0.1 setlinewidth x1 y1 moveto dx len mul dy len mul rlineto stroke"
   807        << "       newpath x1 dy w 2 div mul add y1 dx w 2 div mul sub moveto\n"
   808        << "       len w sub arrl sub dx dy lrl\n"
   809        << "       arrw dy dx neg lrl\n"
   810        << "       dx arrl w add mul dy w 2 div arrw add mul sub\n"
   811        << "       dy arrl w add mul dx w 2 div arrw add mul add rlineto\n"
   812        << "       dx arrl w add mul neg dy w 2 div arrw add mul sub\n"
   813        << "       dy arrl w add mul neg dx w 2 div arrw add mul add rlineto\n"
   814        << "       arrw dy dx neg lrl\n"
   815        << "       len w sub arrl sub neg dx dy lrl\n"
   816        << "       closepath fill } bind def\n";
   817     os << "/cshow { 2 index 2 index moveto dup stringwidth pop\n"
   818        << "         neg 2 div fosi .35 mul neg rmoveto show pop pop} def\n";
   819 
   820     os << "\ngsave\n";
   821     if(_scaleToA4)
   822       if(bb.height()>bb.width()) {
   823 	double sc= std::min((A4HEIGHT-2*A4BORDER)/bb.height(),
   824 		  (A4WIDTH-2*A4BORDER)/bb.width());
   825 	os << ((A4WIDTH -2*A4BORDER)-sc*bb.width())/2 + A4BORDER << ' '
   826 	   << ((A4HEIGHT-2*A4BORDER)-sc*bb.height())/2 + A4BORDER << " translate\n"
   827 	   << sc << " dup scale\n"
   828 	   << -bb.left() << ' ' << -bb.bottom() << " translate\n";
   829       }
   830       else {
   831 	//\todo Verify centering
   832 	double sc= std::min((A4HEIGHT-2*A4BORDER)/bb.width(),
   833 		  (A4WIDTH-2*A4BORDER)/bb.height());
   834 	os << ((A4WIDTH -2*A4BORDER)-sc*bb.height())/2 + A4BORDER << ' '
   835 	   << ((A4HEIGHT-2*A4BORDER)-sc*bb.width())/2 + A4BORDER  << " translate\n"
   836 	   << sc << " dup scale\n90 rotate\n"
   837 	   << -bb.left() << ' ' << -bb.top() << " translate\n";	
   838 	}
   839     else if(_scale!=1.0) os << _scale << " dup scale\n";
   840     
   841     if(_showEdges) {
   842       os << "%Edges:\ngsave\n";      
   843       if(_enableParallel) {
   844 	std::vector<Edge> el;
   845 	for(EdgeIt e(g);e!=INVALID;++e)
   846 	  if((!_undirected||g.source(e)<g.target(e))&&_edgeWidths[e]>0
   847 	     &&g.source(e)!=g.target(e))
   848 	    el.push_back(e);
   849 	std::sort(el.begin(),el.end(),edgeLess(g));
   850 	
   851 	typename std::vector<Edge>::iterator j;
   852 	for(typename std::vector<Edge>::iterator i=el.begin();i!=el.end();i=j) {
   853 	  for(j=i+1;j!=el.end()&&isParallel(*i,*j);++j) ;
   854 
   855 	  double sw=0;
   856 	  for(typename std::vector<Edge>::iterator e=i;e!=j;++e)
   857 	    sw+=_edgeWidths[*e]*_edgeWidthScale+_parEdgeDist;
   858 	  sw-=_parEdgeDist;
   859 	  sw/=-2.0;
   860 	  xy<double> dvec(mycoords[g.target(*i)]-mycoords[g.source(*i)]);
   861 	  double l=std::sqrt(dvec.normSquare()); 
   862 	  ///\todo better 'epsilon' would be nice here.
   863 	  xy<double> d(dvec/std::max(l,1e-9));
   864  	  xy<double> m;
   865 // 	  m=xy<double>(mycoords[g.target(*i)]+mycoords[g.source(*i)])/2.0;
   866 
   867 //  	  m=xy<double>(mycoords[g.source(*i)])+
   868 // 	    dvec*(double(_nodeSizes[g.source(*i)])/
   869 // 	       (_nodeSizes[g.source(*i)]+_nodeSizes[g.target(*i)]));
   870 
   871  	  m=xy<double>(mycoords[g.source(*i)])+
   872 	    d*(l+_nodeSizes[g.source(*i)]-_nodeSizes[g.target(*i)])/2.0;
   873 
   874 	  for(typename std::vector<Edge>::iterator e=i;e!=j;++e) {
   875 	    sw+=_edgeWidths[*e]*_edgeWidthScale/2.0;
   876 	    xy<double> mm=m+rot90(d)*sw/.75;
   877 	    if(_drawArrows) {
   878 	      int node_shape;
   879 	      xy<double> s=mycoords[g.source(*e)];
   880 	      xy<double> t=mycoords[g.target(*e)];
   881 	      double rn=_nodeSizes[g.target(*e)]*_nodeScale;
   882 	      node_shape=_nodeShapes[g.target(*e)];
   883 	      Bezier3 bez(s,mm,mm,t);
   884 	      double t1=0,t2=1;
   885 	      for(int i=0;i<INTERPOL_PREC;++i)
   886 		if(isInsideNode(bez((t1+t2)/2)-t,rn,node_shape)) t2=(t1+t2)/2;
   887 		else t1=(t1+t2)/2;
   888 	      xy<double> apoint=bez((t1+t2)/2);
   889 	      rn = _arrowLength+_edgeWidths[*e]*_edgeWidthScale;
   890 	      rn*=rn;
   891 	      t2=(t1+t2)/2;t1=0;
   892 	      for(int i=0;i<INTERPOL_PREC;++i)
   893 		if((bez((t1+t2)/2)-apoint).normSquare()>rn) t1=(t1+t2)/2;
   894 		else t2=(t1+t2)/2;
   895 	      xy<double> linend=bez((t1+t2)/2);	      
   896 	      bez=bez.before((t1+t2)/2);
   897 // 	      rn=_nodeSizes[g.source(*e)]*_nodeScale;
   898 // 	      node_shape=_nodeShapes[g.source(*e)];
   899 // 	      t1=0;t2=1;
   900 // 	      for(int i=0;i<INTERPOL_PREC;++i)
   901 // 		if(isInsideNode(bez((t1+t2)/2)-t,rn,node_shape)) t1=(t1+t2)/2;
   902 // 		else t2=(t1+t2)/2;
   903 // 	      bez=bez.after((t1+t2)/2);
   904 	      os << _edgeWidths[*e]*_edgeWidthScale << " setlinewidth "
   905 		 << _edgeColors[*e].red() << ' '
   906 		 << _edgeColors[*e].green() << ' '
   907 		 << _edgeColors[*e].blue() << " setrgbcolor newpath\n"
   908 		 << bez.p1.x << ' ' <<  bez.p1.y << " moveto\n"
   909 		 << bez.p2.x << ' ' << bez.p2.y << ' '
   910 		 << bez.p3.x << ' ' << bez.p3.y << ' '
   911 		 << bez.p4.x << ' ' << bez.p4.y << " curveto stroke\n";
   912 	      xy<double> dd(rot90(linend-apoint));
   913 	      dd*=(.5*_edgeWidths[*e]*_edgeWidthScale+_arrowWidth)/
   914 		std::sqrt(dd.normSquare());
   915 	      os << "newpath " << psOut(apoint) << " moveto "
   916 		 << psOut(linend+dd) << " lineto "
   917 		 << psOut(linend-dd) << " lineto closepath fill\n";
   918 	    }
   919 	    else {
   920 	      os << mycoords[g.source(*e)].x << ' '
   921 		 << mycoords[g.source(*e)].y << ' '
   922 		 << mm.x << ' ' << mm.y << ' '
   923 		 << mycoords[g.target(*e)].x << ' '
   924 		 << mycoords[g.target(*e)].y << ' '
   925 		 << _edgeColors[*e].red() << ' '
   926 		 << _edgeColors[*e].green() << ' '
   927 		 << _edgeColors[*e].blue() << ' '
   928 		 << _edgeWidths[*e]*_edgeWidthScale << " lb\n";
   929 	    }
   930 	    sw+=_edgeWidths[*e]*_edgeWidthScale/2.0+_parEdgeDist;
   931 	  }
   932 	}
   933       }
   934       else for(EdgeIt e(g);e!=INVALID;++e)
   935 	if((!_undirected||g.source(e)<g.target(e))&&_edgeWidths[e]>0
   936 	   &&g.source(e)!=g.target(e))
   937 	  if(_drawArrows) {
   938 	    xy<double> d(mycoords[g.target(e)]-mycoords[g.source(e)]);
   939 	    double rn=_nodeSizes[g.target(e)]*_nodeScale;
   940 	    int node_shape=_nodeShapes[g.target(e)];
   941 	    double t1=0,t2=1;
   942 	    for(int i=0;i<INTERPOL_PREC;++i)
   943 	      if(isInsideNode((-(t1+t2)/2)*d,rn,node_shape)) t1=(t1+t2)/2;
   944 	      else t2=(t1+t2)/2;
   945 	    double l=std::sqrt(d.normSquare());
   946 	    d/=l;
   947 	    
   948 	    os << l*(1-(t1+t2)/2) << ' '
   949 	       << _edgeWidths[e]*_edgeWidthScale << ' '
   950 	       << d.x << ' ' << d.y << ' '
   951 	       << mycoords[g.source(e)].x << ' '
   952 	       << mycoords[g.source(e)].y << ' '
   953 	       << _edgeColors[e].red() << ' '
   954 	       << _edgeColors[e].green() << ' '
   955 	       << _edgeColors[e].blue() << " arr\n";
   956 	  }
   957 	  else os << mycoords[g.source(e)].x << ' '
   958 		  << mycoords[g.source(e)].y << ' '
   959 		  << mycoords[g.target(e)].x << ' '
   960 		  << mycoords[g.target(e)].y << ' '
   961 		  << _edgeColors[e].red() << ' '
   962 		  << _edgeColors[e].green() << ' '
   963 		  << _edgeColors[e].blue() << ' '
   964 		  << _edgeWidths[e]*_edgeWidthScale << " l\n";
   965       os << "grestore\n";
   966     }
   967     if(_showNodes) {
   968       os << "%Nodes:\ngsave\n";
   969       for(NodeIt n(g);n!=INVALID;++n) {
   970 	os << mycoords[n].x << ' ' << mycoords[n].y << ' '
   971 	   << _nodeSizes[n]*_nodeScale << ' '
   972 	   << _nodeColors[n].red() << ' '
   973 	   << _nodeColors[n].green() << ' '
   974 	   << _nodeColors[n].blue() << ' ';
   975 	switch(_nodeShapes[n]) {
   976 	case CIRCLE:
   977 	  os<< "nc";break;
   978 	case SQUARE:
   979 	  os<< "nsq";break;
   980 	case DIAMOND:
   981 	  os<< "ndi";break;
   982 	case MALE:
   983 	  os<< "nmale";break;
   984 	case FEMALE:
   985 	  os<< "nfemale";break;
   986 	}
   987 	os<<'\n';
   988       }
   989       os << "grestore\n";
   990     }
   991     if(_showNodeText) {
   992       os << "%Node texts:\ngsave\n";
   993       os << "/fosi " << _nodeTextSize << " def\n";
   994       os << "(Helvetica) findfont fosi scalefont setfont\n";
   995       for(NodeIt n(g);n!=INVALID;++n) {
   996 	switch(_nodeTextColorType) {
   997 	case DIST_COL:
   998 	  os << psOut(distantColor(_nodeColors[n])) << " setrgbcolor\n";
   999 	  break;
  1000 	case DIST_BW:
  1001 	  os << psOut(distantBW(_nodeColors[n])) << " setrgbcolor\n";
  1002 	  break;
  1003 	case CUST_COL:
  1004 	  os << psOut(distantColor(_nodeTextColors[n])) << " setrgbcolor\n";
  1005 	  break;
  1006 	default:
  1007 	  os << "0 0 0 setrgbcolor\n";
  1008 	}
  1009 	os << mycoords[n].x << ' ' << mycoords[n].y
  1010 	   << " (" << _nodeTexts[n] << ") cshow\n";
  1011       }
  1012       os << "grestore\n";
  1013     }
  1014     if(_showNodePsText) {
  1015       os << "%Node PS blocks:\ngsave\n";
  1016       for(NodeIt n(g);n!=INVALID;++n)
  1017 	os << mycoords[n].x << ' ' << mycoords[n].y
  1018 	   << " moveto\n" << _nodePsTexts[n] << "\n";
  1019       os << "grestore\n";
  1020     }
  1021     
  1022     os << "grestore\nshowpage\n";
  1023 
  1024     //CleanUp:
  1025     if(_pleaseRemoveOsStream) {delete &os;}
  1026   } 
  1027 };
  1028 
  1029 template<class T>
  1030 const int GraphToEps<T>::INTERPOL_PREC = 20;
  1031 template<class T>
  1032 const double GraphToEps<T>::A4HEIGHT = 841.8897637795276;
  1033 template<class T>
  1034 const double GraphToEps<T>::A4WIDTH  = 595.275590551181;
  1035 template<class T>
  1036 const double GraphToEps<T>::A4BORDER = 15;
  1037 
  1038 
  1039 ///Generates an EPS file from a graph
  1040 
  1041 ///\ingroup io_group
  1042 ///Generates an EPS file from a graph.
  1043 ///\param g is a reference to the graph to be printed
  1044 ///\param os is a reference to the output stream.
  1045 ///By default it is <tt>std::cout</tt>
  1046 ///
  1047 ///This function also has a lot of
  1048 ///\ref named-templ-func-param "named parameters",
  1049 ///they are declared as the members of class \ref GraphToEps. The following
  1050 ///example shows how to use these parameters.
  1051 ///\code
  1052 /// graphToEps(g,os).scale(10).coords(coords)
  1053 ///              .nodeScale(2).nodeSizes(sizes)
  1054 ///              .edgeWidthScale(.4).run();
  1055 ///\endcode
  1056 ///\warning Don't forget to put the \ref GraphToEps::run() "run()"
  1057 ///to the end of the parameter list.
  1058 ///\sa GraphToEps
  1059 ///\sa graphToEps(G &g, const char *file_name)
  1060 template<class G>
  1061 GraphToEps<DefaultGraphToEpsTraits<G> > 
  1062 graphToEps(G &g, std::ostream& os=std::cout)
  1063 {
  1064   return 
  1065     GraphToEps<DefaultGraphToEpsTraits<G> >(DefaultGraphToEpsTraits<G>(g,os));
  1066 }
  1067  
  1068 ///Generates an EPS file from a graph
  1069 
  1070 ///\ingroup io_group
  1071 ///This function does the same as
  1072 ///\ref graphToEps(G &g,std::ostream& os)
  1073 ///but it writes its output into the file \c file_name
  1074 ///instead of a stream.
  1075 ///\sa graphToEps(G &g, std::ostream& os)
  1076 template<class G>
  1077 GraphToEps<DefaultGraphToEpsTraits<G> > 
  1078 graphToEps(G &g,const char *file_name)
  1079 {
  1080   return GraphToEps<DefaultGraphToEpsTraits<G> >
  1081     (DefaultGraphToEpsTraits<G>(g,*new std::ofstream(file_name),true));
  1082 }
  1083 
  1084 ///Generates an EPS file from a graph
  1085 
  1086 ///\ingroup io_group
  1087 ///This function does the same as
  1088 ///\ref graphToEps(G &g,std::ostream& os)
  1089 ///but it writes its output into the file \c file_name
  1090 ///instead of a stream.
  1091 ///\sa graphToEps(G &g, std::ostream& os)
  1092 template<class G>
  1093 GraphToEps<DefaultGraphToEpsTraits<G> > 
  1094 graphToEps(G &g,const std::string& file_name)
  1095 {
  1096   return GraphToEps<DefaultGraphToEpsTraits<G> >
  1097     (DefaultGraphToEpsTraits<G>(g,*new std::ofstream(file_name.c_str()),true));
  1098 }
  1099 
  1100 } //END OF NAMESPACE LEMON
  1101 
  1102 #endif // LEMON_GRAPH_TO_EPS_H