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