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

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

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

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