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