lemon/graph_to_eps.h
author Peter Kovacs <kpeter@inf.elte.hu>
Fri, 03 Apr 2009 18:59:15 +0200
changeset 608 6ac5d9ae1d3d
parent 509 c5919679af17
parent 482 879c55700cd4
child 559 c5fd2d996909
permissions -rw-r--r--
Support real types + numerical stability fix in NS (#254)

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