lemon/graph_to_eps.h
author deba
Tue, 17 Oct 2006 10:50:57 +0000
changeset 2247 269a0dcee70b
parent 2178 0d7c0f96a5ee
child 2379 248152674a9e
permissions -rw-r--r--
Update the Path concept
Concept check for paths

DirPath renamed to Path
The interface updated to the new lemon interface
Make difference between the empty path and the path from one node
Builder interface have not been changed
// I wanted but there was not accordance about it

UPath is removed
It was a buggy implementation, it could not iterate on the
nodes in the right order
Right way to use undirected paths => path of edges in undirected graphs

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